rm(list = ls())

Dependencies

Packages included:

  • tidyverse - for convenient code flow, data wrangling and plotting
  • rjags & R2jags - to link JAGS and R
  • skimr - for data summary
  • corrr - to output correlation matrices in dataframe format
  • cowplot & patchwork - to combine plot panels
  • Rmarkdown - to produce this neat little documentation
# load pacman package from the repository, if you do not already have it
if (!require('pacman')) install.packages('pacman', repos="https://cloud.r-project.org")
pacman::p_load(tidyverse, # set of packages for data manipulation, exploration and visualisation
               rjags,     # to link JAGS and R
               R2jags,    # to link JAGS and R
               skimr,     # for quick dataframe inspection
               corrr,     # output correlation matrices as data frame
               cowplot,   # combine plot panels
               patchwork, # -"-
               rmarkdown) # for R Markdown formatting

Functions used:

  • effect size plot function

Colour scheme:

theme_darkgreen <- "#13944D"
theme_purple <- "#8757B3"

Overview

This project aims to disentangle drivers of abundance of different shrub species and functional groups in arctic tundra.

Analyses will integrate two levels of variation: plot group \(\times\) taxon level for climatic predictors (derived from downscaled CHELSA data), due to their coarser (90m) resolution, and plot \(\times\) taxon level for plot-level topographic and biotic interaction predictors.

The total dataset comprises 4968 observations for 66 variables (data compilation is documented in scripts/jonathan/nuuk_shrub_drivers_data_compilation.R):

env_cov_bio <- read.csv(file.path("..", "data", "processed", "nuuk_env_cover_plots.csv"), header = T)

Data preparation for JAGS models

a) selection of variables relevant for analysis

including predictors

  • Information on site, plot, plot group, sampling location (lat, lon, altitude), sampling year
  • downscaled CHELSA predictors, averaged over a 30-year period (*[…]_ts_30*)
  • solar radiation index (SRI, following Keating et al. 2007), slope (erosion measure), Terrain Ruggedness Index (TRI, following Riley et al. 1999), Tasseled Cap Wetness Index (TCWI, Crist & Ciccone 1984), Topographic Wetness Index (TWI, see Conrad et al. 2015) based on FD8-Quinn and SAGA-internal flow algorithms, respectively
  • cover of other shrub species (only used in species models)
  • cover of graminoids
  • competition pressure in the community (as summed abundance of taller-growing shrub species within a plot, averaged within plot groups)
  • taxon (see below for levels)

and response variable

  • cover (as relative no. hits per plot for each species/group)
env_cov_bio_sub <- env_cov_bio %>% 
  select(site_alt_plotgroup_id, plot, site, site_alt_id, year, long, lat, alt,  # plot info / metadata
  ends_with("_ts_30"),        # CHELSA predictors averaged over 30-year period prior to study year
  inclin_down, sri, tcws, tri, # environmental data
  ends_with("_cover"), compet,# biotic predictors: shrub & cover, relative competitiveness/acquisitiveness
  taxon, cover)               # taxon, cover response
head(env_cov_bio_sub)

Let’s check for correlation between the different moisture predictors and terrain ruggedness:

(cor_moist <- env_cov_bio %>% 
  select(twi_fd8, twi_saga, tcws, tri)) %>% 
  correlate(diagonal = 1)

Correlation method: 'pearson'
Missing treated using: 'pairwise.complete.obs'

\(\Rightarrow\) The two TWI are highly correlated with each other, and also rather highly correlated with TRI. All three are largely independent from TCWS. For this alternative pathway, we’ll go with TCWS to illustrate differences in model outcomes with different wetness predictors. Caution: as pointed out by reviewers, reflectance-based TCWS can be confounded by vegetation, though this might also make it more ‘evidential’ than the terrain-based TWI.


Predictors don’t always vary between plots within plotgroups - perhaps due to several falling into the same CHELSA grid cell.

Example: plots within site 1, altitude 20, plot group 1: plot P146 is slightly off and therefore has different climate variables than the other ones

Therefore plotgroup-scale (climatic) predictors will have to be averaged before using in models!

env_cov_bio %>% filter(taxon == "Betula nana" & site_alt_plotgroup_id == "1_20_1") %>% 
  ggplot(aes(x = long, y = lat)) + 
  geom_point() + 
  geom_text(aes(label = plot), hjust = 0.0001) + 
  xlim(c(-51.78675, -51.7863))

env_cov_bio %>% filter(taxon == "Betula nana" & site_alt_plotgroup_id == "1_20_1") %>% 
  select(site_alt_plotgroup_id, plot, tempjja_ts_30)

Check for correlation between predictors:

predictors_set <- env_cov_bio_sub %>% 
  select(ends_with("_ts_30"),   # CHELSA predictors averaged over 10-year period prior to study year
         inclin_down, sri, tri, tcws,      # environmental data
         shrub_cover, graminoid_cover, compet) %>%  # biotic predictors
  names()
# create basic correlation matrix
(cor_mat <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set) %>% 
  correlate(diagonal = 1) %>% 
  # drop all values < .4 to increase readability
  mutate_if(is.numeric, ~ ifelse(abs(.) < .4, NA, .)))

Correlation method: 'pearson'
Missing treated using: 'pairwise.complete.obs'

\(\Rightarrow\) Maximum temperature is highly correlated with summer temperature, minimum temperature with continentality, slope (inclin_down) with solar radiation, and spring precipitation variables with summer precipitation. Let’s exclude them step by step and check the variance inflation factors (VIF) along the way. VIF values > 5 indicate collinearity issues.

# for the whole set of predictors
(vif_predictors_1 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set) %>% 
  usdm::vif()) #%>% View()
# => drop tempmax (correlated w/ tempjja)
(vif_predictors_2 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30) %>% 
  usdm::vif()) #%>% View()
# => drop tempmin (correlated w/ tempcont)
(vif_predictors_3 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30) %>% 
  usdm::vif()) #%>% View()
# => drop precipjfmam (correlated w/ precipjja & tempcont)
(vif_predictors_4 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30,
                -contains("jfm")) %>% 
  usdm::vif()) #%>% View()
# => drop inclin_down (correlated w/ SRI)
(vif_predictors_5 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30,
                -inclin_down,
                -contains("jfm")) %>% 
  usdm::vif()) #%>% View()
# => drop precipmam (correlated w/ precipjja)
(vif_predictors_6 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30,
                -inclin_down,
                -contains("mam")) %>% 
  usdm::vif()) #%>% View()

All VIF are now < 3 -> OK! We can now exclude the dropped variables to obtain the final dataset. In addition, we rename the climate variables and delete the extension:

env_cov_bio_sub <- env_cov_bio_sub %>% 
  dplyr::select(-tempmax_ts_30,
                -tempmin_ts_30,
                -inclin_down,
                -contains("mam")) %>% 
  
  rename(tempjja = tempjja_ts_30,
         tempcont = tempcont_ts_30,
         precipjja = precipjja_ts_30) %>% 
  
  mutate(taxon = as.factor(taxon))
str(env_cov_bio_sub)
'data.frame':   4968 obs. of  28 variables:
 $ site_alt_plotgroup_id: chr  "1_20_1" "1_20_1" "1_20_1" "1_20_1" ...
 $ plot                 : chr  "P145" "P145" "P145" "P145" ...
 $ site                 : int  1 1 1 1 1 1 1 1 1 1 ...
 $ site_alt_id          : chr  "1_20" "1_20" "1_20" "1_20" ...
 $ year                 : int  2011 2011 2011 2011 2011 2011 2011 2011 2011 2011 ...
 $ long                 : num  -51.8 -51.8 -51.8 -51.8 -51.8 ...
 $ lat                  : num  64.2 64.2 64.2 64.2 64.2 ...
 $ alt                  : int  20 20 20 20 20 20 20 20 20 20 ...
 $ tempjja              : num  9.35 9.35 9.35 9.35 9.35 ...
 $ tempcont             : num  24.9 24.9 24.9 24.9 24.9 ...
 $ precipjja            : num  214 214 214 214 214 ...
 $ sri                  : num  0.933 0.933 0.933 0.933 0.933 ...
 $ tcws                 : num  -992 -992 -992 -992 -992 ...
 $ tri                  : num  0.28 0.28 0.28 0.28 0.28 ...
 $ graminoid_cover      : num  0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 ...
 $ shrub_cover          : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ BetNan_shrub_cover   : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ CasTet_shrub_cover   : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ EmpNig_shrub_cover   : num  0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 ...
 $ PhyCae_shrub_cover   : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ RhoGro_shrub_cover   : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ RhoTom_shrub_cover   : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ SalArc_shrub_cover   : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ SalGla_shrub_cover   : num  0.72 0.72 0.72 0.72 0.72 0.72 0.72 0.72 0.72 0.72 ...
 $ VacUli_shrub_cover   : num  0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 0.92 ...
 $ compet               : num  0.5988 -0.1508 -0.2 -0.0619 -0.0619 ...
 $ taxon                : Factor w/ 12 levels "All deciduous",..: 4 5 6 8 9 7 11 10 12 3 ...
 $ cover                : num  0 0 0.72 0 0 0 0.2 0 0 0.92 ...

b) adjustion of data structure

Data is ordered by site/altitude/plotgroup and taxon

env_cov_bio_sub <- env_cov_bio_sub[order(env_cov_bio_sub$site_alt_plotgroup_id, env_cov_bio_sub$taxon),]

As JAGS is only able to handle numeric input, all variables are assigned a numeric identifier:

env_cov_bio_sub$plotgroup.NUM <- as.numeric(factor(env_cov_bio_sub$site_alt_plotgroup_id,
                                                   levels = unique(env_cov_bio_sub$site_alt_plotgroup_id)))
env_cov_bio_sub$plot.NUM <- as.numeric(factor(env_cov_bio_sub$plot,
                                              levels = unique(env_cov_bio_sub$plot)))
env_cov_bio_sub$site_alt.NUM <- as.numeric(factor(env_cov_bio_sub$site_alt_id,
                                              levels = unique(env_cov_bio_sub$site_alt_id)))
env_cov_bio_sub$site.NUM <- as.numeric(factor(env_cov_bio_sub$site, levels = unique(env_cov_bio_sub$site)))
env_cov_bio_sub$taxon.NUM <- as.numeric(factor(env_cov_bio_sub$taxon, levels = unique(env_cov_bio_sub$taxon)))

Taxa were coded as follows:

data.frame(taxon = levels(env_cov_bio_sub$taxon),
           num = unique(env_cov_bio_sub$taxon.NUM))

Numeric predictors were scaled and centered:

num_pred <- env_cov_bio_sub %>% select(tempjja,
                                       tempcont,
                                       precipjja,
                                       sri, 
                                       tcws,
                                       tri, 
                                       ends_with("_cover"),
                                       matches("compet"))
for(i in 1:length(num_pred)){
  col <- colnames(num_pred[i])
  env_cov_bio_sub[paste0(col,"C")] <- as.numeric(scale(num_pred[i], scale = TRUE, center = TRUE))
}

To account for the range of the cover response (\(0 \leq cover \leq 1\)), the model needs a mixed structure incorporating a beta distribution (for all continuous values with \(0 < cover < 1\)) and a binomial distribution (for all discrete values of \(cover = \{0, 1\}\)). An additional variable cover_discrete was introduced to separate the dataset into discrete (= 1) and continuous (= 0) cover values:

env_cov_bio_sub$cover_discrete <- ifelse(env_cov_bio_sub$cover == 1 | env_cov_bio_sub$cover == 0, 1, 0)


JAGS models

The dataset was then ready to be split up into the species of interest. We create separate data subsets for all/discrete/continuous response variable values for each species:

# split dataframe by taxon
env_cov_bio_sub_spec.tot <- split(env_cov_bio_sub, env_cov_bio_sub$taxon)

# assign taxon name to list elements
# >> for total datasets
for (taxon_id in 1:nlevels(env_cov_bio_sub$taxon)){
  # extract 3-letter genus name string
  assign(paste0(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id], 
                            "^\\w{3}"),
  # extract and capitalise 3-letter species name string
                str_to_title(str_remove(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id],
                                                    "\\s\\w{3}"),
                                        "\\s")),
  # add extension
                ".tot"),
  # assign to respective list element
         env_cov_bio_sub_spec.tot[[taxon_id]])
}



# >> for discrete datasets
env_cov_bio_sub_spec.dis <- list()
for (taxon_id in 1:nlevels(env_cov_bio_sub$taxon)){
  # filter for discrete response values
  env_cov_bio_sub_spec.dis[[taxon_id]] <- filter(env_cov_bio_sub_spec.tot[[taxon_id]], cover_discrete == 1)
  # extract 3-letter genus name string
  assign(paste0(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id], 
                            "^\\w{3}"),
  # extract and capitalise 3-letter species name string
                str_to_title(str_remove(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id],
                                                    "\\s\\w{3}"),
                                        "\\s")),
  # add extension
                ".dis"),
  # assign to respective list element
         env_cov_bio_sub_spec.dis[[taxon_id]])
}

# >> for continuous datasets
env_cov_bio_sub_spec.cont <- list()
for (taxon_id in 1:nlevels(env_cov_bio_sub$taxon)){
  # filter for continuous response values
  env_cov_bio_sub_spec.cont[[taxon_id]] <- filter(env_cov_bio_sub_spec.tot[[taxon_id]], cover_discrete == 0)
  # extract 3-letter genus name string
  assign(paste0(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id], 
                            "^\\w{3}"),
  # extract and capitalise 3-letter species name string
                str_to_title(str_remove(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id],
                                                    "\\s\\w{3}"),
                                        "\\s")),
  # add extension
                ".cont"),
  # assign to respective list element
         env_cov_bio_sub_spec.cont[[taxon_id]])
}

# save all input data
# groups
save(list = c("AllShr.tot",
              "AllEve.tot",
              "AllDec.tot"),
     file = file.path("..", "data", "processed", "model_input_data_tcws", "shrub_gradient_group.datasets.Rdata"))

# species
# groups
save(list = c("BetNan.tot",
              "CasTet.tot",
              "EmpNig.tot",
              "PhyCae.tot",
              "RhoGro.tot",
              "RhoTom.tot",
              "SalArc.tot",
              "SalGla.tot",
              "VacUli.tot"),
     file = file.path("..", "data", "processed", "model_input_data_tcws", "shrub_gradient_species.datasets.Rdata"))

Groups

> assembling data for model input in lists

JAGS needs data input in list format, so all relevant variables are compiled into lists:

# Compile data into lists
# All shrubs ----
shrub_gradient_jags.AllShr.data <- list(
  
  # plot level predictors
  cov.tot = AllShr.tot$cover + 1,
  plotgroup.tot = AllShr.tot$plotgroup.NUM,
  sri.tot = AllShr.tot$sriC,
  tri.tot = AllShr.tot$triC,
  tcws.tot = AllShr.tot$tcwsC,
  gramin_cov.tot = AllShr.tot$graminoid_coverC,
  tempjja.tot.plot = AllShr.tot$tempjjaC,
  N_plots = length(unique(AllShr.tot$plot)),
  
  # plot group level predictors
  tempjja.tot = AllShr.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = AllShr.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = AllShr.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(AllShr.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_graminoid_cover = seq(from = min(AllShr.tot$graminoid_coverC), to = max(AllShr.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(AllShr.tot$sriC), to = max(AllShr.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(AllShr.tot$triC), to = max(AllShr.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(AllShr.tot$tcwsC), to = max(AllShr.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(AllShr.tot$tempjjaC), to = max(AllShr.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(AllShr.tot$precipjjaC), to = max(AllShr.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(AllShr.tot$tempcontC), to = max(AllShr.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(AllShr.tot$tcwsC,0.05),quantile(AllShr.tot$tcwsC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.AllShr.data)
List of 22
 $ cov.tot             : num [1:414] 1.52 1.84 1.6 1.72 1.52 1.2 1 1.16 1.64 1 ...
 $ plotgroup.tot       : num [1:414] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.tot             : num [1:414] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.tot             : num [1:414] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.tot            : num [1:414] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ gramin_cov.tot      : num [1:414] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ tempjja.tot.plot    : num [1:414] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ N_plots             : int 414
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -1.62 1.62
 $ Nxhat2              : num 2
# All evergreen shrubs ----
shrub_gradient_jags.AllEve.data <- list(
  
  # plot level predictors
  cov.tot = AllEve.tot$cover + 1,
  plotgroup.tot = AllEve.tot$plotgroup.NUM,
  sri.tot = AllEve.tot$sriC,
  tri.tot = AllEve.tot$triC,
  tcws.tot = AllEve.tot$tcwsC,
  gramin_cov.tot = AllEve.tot$graminoid_coverC,
  tempjja.tot.plot = AllEve.tot$tempjjaC,
  N_plots = length(unique(AllEve.tot$plot)),
  
  # plot group level predictors
  tempjja.tot = AllEve.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = AllEve.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = AllEve.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(AllEve.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_graminoid_cover = seq(from = min(AllEve.tot$graminoid_coverC), to = max(AllEve.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(AllEve.tot$sriC), to = max(AllEve.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(AllEve.tot$triC), to = max(AllEve.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(AllEve.tot$tcwsC), to = max(AllEve.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(AllEve.tot$tempjjaC), to = max(AllEve.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(AllEve.tot$precipjjaC), to = max(AllEve.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(AllEve.tot$tempcontC), to = max(AllEve.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(AllEve.tot$tcwsC,0.05),quantile(AllEve.tot$tcwsC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.AllEve.data)
List of 22
 $ cov.tot             : num [1:414] 1.52 1.84 1.6 1.64 1.52 1.16 1 1.16 1.64 1 ...
 $ plotgroup.tot       : num [1:414] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.tot             : num [1:414] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.tot             : num [1:414] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.tot            : num [1:414] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ gramin_cov.tot      : num [1:414] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ tempjja.tot.plot    : num [1:414] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ N_plots             : int 414
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -1.62 1.62
 $ Nxhat2              : num 2
# All decidious shrubs ----
shrub_gradient_jags.AllDec.data <- list(
  
  # plot level predictors
  cov.tot = AllDec.tot$cover + 1,
  plotgroup.tot = AllDec.tot$plotgroup.NUM,
  sri.tot = AllDec.tot$sriC,
  tri.tot = AllDec.tot$triC,
  tcws.tot = AllDec.tot$tcwsC,
  gramin_cov.tot = AllDec.tot$graminoid_coverC,
  tempjja.tot.plot = AllDec.tot$tempjjaC,
  N_plots = length(unique(AllDec.tot$plot)),
  
  # plot group level predictors
  tempjja.tot = AllDec.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = AllDec.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = AllDec.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(AllDec.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_graminoid_cover = seq(from = min(AllDec.tot$graminoid_coverC), to = max(AllDec.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(AllDec.tot$sriC), to = max(AllDec.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(AllDec.tot$triC), to = max(AllDec.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(AllDec.tot$tcwsC), to = max(AllDec.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(AllDec.tot$tempjjaC), to = max(AllDec.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(AllDec.tot$precipjjaC), to = max(AllDec.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(AllDec.tot$tempcontC), to = max(AllDec.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(AllDec.tot$tcwsC,0.05),quantile(AllDec.tot$tcwsC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.AllDec.data)
List of 22
 $ cov.tot             : num [1:414] 1 1 1 1.08 1 1.04 1 1 1 1 ...
 $ plotgroup.tot       : num [1:414] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.tot             : num [1:414] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.tot             : num [1:414] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.tot            : num [1:414] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ gramin_cov.tot      : num [1:414] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ tempjja.tot.plot    : num [1:414] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ N_plots             : int 414
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -1.62 1.62
 $ Nxhat2              : num 2
# # save model input data
# shrub_gradient_jags.groupdata <- list

save(list = c("shrub_gradient_jags.AllShr.data",
              "shrub_gradient_jags.AllEve.data",
              "shrub_gradient_jags.AllDec.data"),
     file = file.path("..", "data", "processed", "model_input_data_tcws", "shrub_gradient_jags.groupdata.Rdata"))

> specifying model

write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plot ~ dunif(0,100)
      tau.plot <- 1/(sigma.plot * sigma.plot)
      
      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      b.tempXtcws2 ~ dnorm(0, 0.001)
      
      
    # plot level

      for (i in 1:N_plots){ 
        cov.tot[i] ~ dlnorm(mu.plot[i], tau.plot)
        log(mu.plot[i]) <- b_plotgroup[plotgroup.tot[i]] + # ~= random effect of plot group
                        b.gramin_cov * gramin_cov.tot[i] + 
                        b.tcws * tcws.tot[i] + 
                        b.tempXtcws * tempjja.tot.plot[i] * tcws.tot[i] +       # for interaction
                        b.tempXtcws2 * (tempjja.tot.plot[i]^2) * tcws.tot[i] +  # for interaction
                        b.sri * sri.tot[i] +
                        b.tri * tri.tot[i]
      }

    # plot group level
    
      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] + 
                    b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] +
                                      b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
        }
      }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.groups.jags"))

Specify the parameters to be monitored:

params_groups <- c("intercept",
                   "b.tempjja.x", "b.tempjja.x2",
                   "b.tempcont.x", "b.tempcont.x2",
                   "b.precipjja.x", "b.precipjja.x2",
                   "b.gramin_cov",
                   "b.sri",
                   "b.tri",
                   "b.tcws",
                   "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                   "sigma.plotgroup",
                   "phat_graminoid_cover", 
                   "phat_sri", "phat_tcws", "phat_tri", 
                   "phat_tempjja", "phat_tempcont", "phat_precipjja",
                   "phat_tempXmoist")

> run & evaluate model


All shrubs

# run model
model_out.shrub_gradient.AllShr <- jags(shrub_gradient_jags.AllShr.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_groups,                      # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.groups.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 

# plot(model_out.shrub_gradient.AllShr) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.AllShr <- model_out.shrub_gradient.AllShr$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.AllShr),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.AllShr <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.AllShr$BUGSoutput$sims.list)-4)){
  ci_90.AllShr[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.AllShr$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.AllShr[param, 3] <- names(data.frame(model_out.shrub_gradient.AllShr$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.AllShr <- coeff.shrub_gradient.AllShr %>% 
  left_join(ci_90.AllShr, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.AllShr, 
     file = file.path("..", "data", "processed", "model_outputs", "groups_tcws", "first_runs_converged", "model_output_AllShr.Rdata"))

(effect_size_plot.AllShr <- model_plot_sig_function(coeff.shrub_gradient.AllShr, title_string = "all shrubs", plot_width = 10.5))

  • positive relationship with TC wetness, negative response to graminoid cover (sig.)
  • slightly positive response to solar radiation (n.s.)


As none of the quadratic terms for climatic variables came out significant, re-run without them:

write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plot ~ dunif(0,100)
      tau.plot <- 1/(sigma.plot * sigma.plot)
      
      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      # b.tempXtcws2 ~ dnorm(0, 0.001)
      
      
    # plot level

      for (i in 1:N_plots){ 
        cov.tot[i] ~ dlnorm(mu.plot[i], tau.plot)
        log(mu.plot[i]) <- b_plotgroup[plotgroup.tot[i]] + # ~= random effect of plot group
                        b.gramin_cov * gramin_cov.tot[i] + 
                        b.tcws * tcws.tot[i] + 
                        b.tempXtcws * tempjja.tot.plot[i] * tcws.tot[i] +       # for interaction
                        # b.tempXtcws2 * (tempjja.tot.plot[i]^2) * tcws.tot[i] +  # for interaction
                        b.sri * sri.tot[i] +
                        b.tri * tri.tot[i]
      }

    # plot group level
    
      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] # + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] # + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      # b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] # +
                                      # b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
        }
      }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.AllShr2.jags"))

# specify new set of parameters
params_AllShr2 <- c("intercept",
                   "b.tempjja.x", # "b.tempjja.x2",
                   "b.tempcont.x", # "b.tempcont.x2",
                   "b.precipjja.x", # "b.precipjja.x2",
                   "b.gramin_cov",
                   "b.sri",
                   "b.tri",
                   "b.tcws",
                   "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                   "sigma.plotgroup",
                   "phat_graminoid_cover", 
                   "phat_sri", "phat_tcws", "phat_tri", 
                   "phat_tempjja", "phat_tempcont", "phat_precipjja",
                   "phat_tempXmoist")

# run model
model_out.shrub_gradient.AllShr2 <- jags(shrub_gradient_jags.AllShr.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_AllShr2,                      # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.AllShr2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 

# plot(model_out.shrub_gradient.AllShr2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.AllShr2 <- model_out.shrub_gradient.AllShr2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.AllShr2),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.AllShr2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.AllShr2$BUGSoutput$sims.list)-4)){
  ci_90.AllShr2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.AllShr2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.AllShr2[param, 3] <- names(data.frame(model_out.shrub_gradient.AllShr2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.AllShr2 <- coeff.shrub_gradient.AllShr2 %>% 
  left_join(ci_90.AllShr2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.AllShr2, file = file.path("..", "data", "processed", "model_outputs", "groups_tcws", "model_output_AllShr2.Rdata"))

(effect_size_plot.AllShr2 <- model_plot_sig_function(coeff.shrub_gradient.AllShr2, title_string = "all shrubs", plot_width = 7.5))

  • positive response to TC wetness, negative response to graminoid cover (sig.)
  • positive response to precipitation and solar radiation, negative to terrain heterogeneity (n.s.)


Evergreen shrubs

# run model
model_out.shrub_gradient.AllEve <- jags(shrub_gradient_jags.AllEve.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_groups,                      # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.groups.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 

# plot(model_out.shrub_gradient.AllEve) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.AllEve <- model_out.shrub_gradient.AllEve$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.AllEve),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.AllEve <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.AllEve$BUGSoutput$sims.list)-4)){
  ci_90.AllEve[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.AllEve$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.AllEve[param, 3] <- names(data.frame(model_out.shrub_gradient.AllEve$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.AllEve <- coeff.shrub_gradient.AllEve %>% 
  left_join(ci_90.AllEve, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.AllEve, file = file.path("..", "data", "processed", "model_outputs", "groups_tcws", "first_runs_converged", "model_output_AllEve.Rdata"))

(effect_size_plot.AllEve <- model_plot_sig_function(coeff.shrub_gradient.AllEve, title_string = "evergreen shrubs", plot_width = 10.5))

  • unimodal relationship with temperature, positive with TC wetness, negative with graminoid cover (sig.)
  • slightly positive response to solar radiation, slightly unimodal relationship with precipitation (n.s.)


write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plot ~ dunif(0,100)
      tau.plot <- 1/(sigma.plot * sigma.plot)
      
      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      b.tempXtcws2 ~ dnorm(0, 0.001)
      
      
    # plot level

      for (i in 1:N_plots){ 
        cov.tot[i] ~ dlnorm(mu.plot[i], tau.plot)
        log(mu.plot[i]) <- b_plotgroup[plotgroup.tot[i]] + # ~= random effect of plot group
                        b.gramin_cov * gramin_cov.tot[i] + 
                        b.tcws * tcws.tot[i] + 
                        b.tempXtcws * tempjja.tot.plot[i] * tcws.tot[i] +       # for interaction
                        b.tempXtcws2 * (tempjja.tot.plot[i]^2) * tcws.tot[i] +  # for interaction
                        b.sri * sri.tot[i] +
                        b.tri * tri.tot[i]
      }

    # plot group level
    
      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] # + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] +
                                      b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
        }
      }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.AllEve2.jags"))

# specify new set of parameters
params_AllEve2 <- c("intercept",
                   "b.tempjja.x", "b.tempjja.x2",
                   "b.tempcont.x", # "b.tempcont.x2",
                   "b.precipjja.x", # "b.precipjja.x2",
                   "b.gramin_cov",
                   "b.sri",
                   "b.tri",
                   "b.tcws",
                   "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                   "sigma.plotgroup",
                   "phat_graminoid_cover", 
                   "phat_sri", "phat_tcws", "phat_tri", 
                   "phat_tempjja", "phat_tempcont", "phat_precipjja",
                   "phat_tempXmoist")

# run model
model_out.shrub_gradient.AllEve2 <- jags(shrub_gradient_jags.AllEve.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_AllEve2,                      # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.AllEve2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 

# plot(model_out.shrub_gradient.AllShr2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.AllEve2 <- model_out.shrub_gradient.AllEve2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.AllEve),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.AllEve2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.AllEve2$BUGSoutput$sims.list)-4)){
  ci_90.AllEve2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.AllEve2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.AllEve2[param, 3] <- names(data.frame(model_out.shrub_gradient.AllEve2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.AllEve2 <- coeff.shrub_gradient.AllEve2 %>% 
  left_join(ci_90.AllEve2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.AllEve2, file = file.path("..", "data", "processed", "model_outputs", "groups_tcws", "model_output_AllEve2.Rdata"))

(effect_size_plot.AllEve2 <- model_plot_sig_function(coeff.shrub_gradient.AllEve2, title_string = "evergreen shrubs", plot_width = 8.5))

  • unimodal response to temperature, negative response to graminoid cover and temp. variability, positive relationship with TCwetness (sig.)
  • slightly positive response to solar radiation (n.s.)


Deciduous shrubs

# run model
model_out.shrub_gradient.AllDec <- jags(shrub_gradient_jags.AllDec.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_groups,                      # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.groups.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 

# plot(model_out.shrub_gradient.AllDec) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.AllDec <- model_out.shrub_gradient.AllDec$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.AllDec),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.AllDec <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.AllDec$BUGSoutput$sims.list)-4)){
  ci_90.AllDec[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.AllDec$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.AllDec[param, 3] <- names(data.frame(model_out.shrub_gradient.AllDec$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.AllDec <- coeff.shrub_gradient.AllDec %>% 
  left_join(ci_90.AllDec, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.AllDec, file = file.path("..", "data", "processed", "model_outputs", "groups_tcws", "first_runs_converged", "model_output_AllDec.Rdata"))

(effect_size_plot.AllDec <- model_plot_sig_function(coeff.shrub_gradient.AllDec, title_string = "deciduous shrubs", plot_width = 10.5))

  • positive/unimodal response to temp. variability, negative response to graminoid cover (sig.)
  • positive relationship with solar radiation, wetness; negative with terrain heterogeneity (m.s.)


write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plot ~ dunif(0,100)
      tau.plot <- 1/(sigma.plot * sigma.plot)
      
      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      b.tempXtcws2 ~ dnorm(0, 0.001)
      
      
    # plot level

      for (i in 1:N_plots){ 
        cov.tot[i] ~ dlnorm(mu.plot[i], tau.plot)
        log(mu.plot[i]) <- b_plotgroup[plotgroup.tot[i]] + # ~= random effect of plot group
                        b.gramin_cov * gramin_cov.tot[i] + 
                        b.tcws * tcws.tot[i] + 
                        b.tempXtcws * tempjja.tot.plot[i] * tcws.tot[i] +       # for interaction
                        # b.tempXtcws2 * (tempjja.tot.plot[i]^2) * tcws.tot[i] +  # for interaction
                        b.sri * sri.tot[i] +
                        b.tri * tri.tot[i]
      }

    # plot group level
    
      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] # + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      # b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] # +
                                      # b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
        }
      }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.AllDec2.jags"))

# specify new set of parameters
params_AllDec2 <- c("intercept",
                   "b.tempjja.x", # "b.tempjja.x2",
                   "b.tempcont.x", "b.tempcont.x2",
                   "b.precipjja.x", # "b.precipjja.x2",
                   "b.gramin_cov",
                   "b.sri",
                   "b.tri",
                   "b.tcws",
                   "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                   "sigma.plotgroup",
                   "phat_graminoid_cover", 
                   "phat_sri", "phat_tcws", "phat_tri", 
                   "phat_tempjja", "phat_tempcont", "phat_precipjja",
                   "phat_tempXmoist")

# run model
model_out.shrub_gradient.AllDec2 <- jags(shrub_gradient_jags.AllDec.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_AllDec2,                      # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.AllDec2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 

# plot(model_out.shrub_gradient.AllDec2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.AllDec2 <- model_out.shrub_gradient.AllDec2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.AllDec2),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.AllDec2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.AllDec2$BUGSoutput$sims.list)-4)){
  ci_90.AllDec2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.AllDec2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.AllDec2[param, 3] <- names(data.frame(model_out.shrub_gradient.AllDec2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.AllDec2 <- coeff.shrub_gradient.AllDec2 %>% 
  left_join(ci_90.AllDec2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.AllDec2, file = file.path("..", "data", "processed", "model_outputs", "groups_tcws", "model_output_AllDec2.Rdata"))

(effect_size_plot.AllDec2 <- model_plot_marg_function(coeff.shrub_gradient.AllDec2, title_string = "deciduous shrubs", plot_width = 8.5))

  • positive/unimodal relationship with temperature variability, negative relationship with graminoid cover, positive relationship with TC wetness and summer temperature (sig.)
  • positive relationship with solar radiation, negative with terrain heterogeneity (m.s.)


Species

> species: assembling data for model input in lists

# BetNan ----
shrub_gradient_jags.BetNan.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = BetNan.dis$cover,
  plotgroup.dis = BetNan.dis$plotgroup.NUM,
  tempjja.dis = BetNan.dis$tempjjaC,
  sri.dis = BetNan.dis$sriC,
  tri.dis = BetNan.dis$triC,
  tcws.dis = BetNan.dis$tcwsC,
  shrub_cov.dis = BetNan.dis$BetNan_shrub_coverC,
  gramin_cov.dis = BetNan.dis$graminoid_coverC,
  compet.dis = BetNan.dis$competC,
  N_discrete = nrow(BetNan.dis),
  
  # ...and continuous part of the data
  cov.cont = BetNan.cont$cover,
  plotgroup.cont = BetNan.cont$plotgroup.NUM,
  tempjja.cont = BetNan.cont$tempjjaC,
  sri.cont = BetNan.cont$sriC,
  tri.cont = BetNan.cont$triC,
  tcws.cont = BetNan.cont$tcwsC,
  shrub_cov.cont = BetNan.cont$BetNan_shrub_coverC,
  gramin_cov.cont = BetNan.cont$graminoid_coverC,
  compet.cont = BetNan.cont$competC,
  N_cont = nrow(BetNan.cont),
  
  # plot group level predictors
  tempjja.tot = BetNan.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = BetNan.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = BetNan.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(BetNan.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(BetNan.tot$competC), to = max(BetNan.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(BetNan.tot$BetNan_shrub_coverC), to = max(BetNan.tot$BetNan_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(BetNan.tot$graminoid_coverC), to = max(BetNan.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(BetNan.tot$sriC), to = max(BetNan.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(BetNan.tot$triC), to = max(BetNan.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(BetNan.tot$tcwsC), to = max(BetNan.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(BetNan.tot$tempjjaC), to = max(BetNan.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(BetNan.tot$precipjjaC), to = max(BetNan.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(BetNan.tot$tempcontC), to = max(BetNan.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(BetNan.tot$tcwsC,0.05),quantile(BetNan.tot$tcwsC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.BetNan.data)
List of 36
 $ cov.dis             : num [1:223] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:223] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.dis         : num [1:223] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.dis             : num [1:223] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis             : num [1:223] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.dis            : num [1:223] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.dis       : num [1:223] 0.451 1.316 0.668 0.992 0.451 ...
 $ gramin_cov.dis      : num [1:223] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:223] 1.33 1.33 1.33 1.19 1.33 ...
 $ N_discrete          : int 223
 $ cov.cont            : num [1:191] 0.08 0.04 0.08 0.12 0.08 0.56 0.24 0.2 0.08 0.12 ...
 $ plotgroup.cont      : num [1:191] 5 5 6 10 10 11 11 11 11 12 ...
 $ tempjja.cont        : num [1:191] -0.42 -0.42 -0.322 1.009 1.009 ...
 $ sri.cont            : num [1:191] 0.823 -0.248 -0.663 -0.678 -0.192 ...
 $ tri.cont            : num [1:191] 0.4531 0.3713 -0.0771 -0.2698 0.1189 ...
 $ tcws.cont           : num [1:191] 0.176 -0.508 -0.83 -2.449 -2.548 ...
 $ shrub_cov.cont      : num [1:191] 2.397 1.1 -0.197 -0.629 -0.954 ...
 $ gramin_cov.cont     : num [1:191] 0.965 -0.582 -0.582 -0.195 -0.195 ...
 $ compet.cont         : num [1:191] 0.486 1.33 1.33 1.33 1.33 ...
 $ N_cont              : int 191
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -0.543 -0.524 -0.505 -0.487 -0.468 ...
 $ xhat_shrub_cover    : num [1:100] -0.954 -0.905 -0.855 -0.806 -0.757 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -1.62 1.62
 $ Nxhat2              : num 2
# CasTet ----
shrub_gradient_jags.CasTet.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = CasTet.dis$cover,
  plotgroup.dis = CasTet.dis$plotgroup.NUM,
  tempjja.dis = CasTet.dis$tempjjaC,
  sri.dis = CasTet.dis$sriC,
  tri.dis = CasTet.dis$triC,
  tcws.dis = CasTet.dis$tcwsC,
  shrub_cov.dis = CasTet.dis$CasTet_shrub_coverC,
  gramin_cov.dis = CasTet.dis$graminoid_coverC,
  compet.dis = CasTet.dis$competC,
  N_discrete = nrow(CasTet.dis),
  
  # ...and continuous part of the data
  cov.cont = CasTet.cont$cover,
  plotgroup.cont = CasTet.cont$plotgroup.NUM,
  tempjja.cont = CasTet.cont$tempjjaC,
  sri.cont = CasTet.cont$sriC,
  tri.cont = CasTet.cont$triC,
  tcws.cont = CasTet.cont$tcwsC,
  shrub_cov.cont = CasTet.cont$CasTet_shrub_coverC,
  gramin_cov.cont = CasTet.cont$graminoid_coverC,
  compet.cont = CasTet.cont$competC,
  N_cont = nrow(CasTet.cont),
  
  # plot group level predictors
  tempjja.tot = CasTet.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = CasTet.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = CasTet.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(CasTet.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(CasTet.tot$competC), to = max(CasTet.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(CasTet.tot$CasTet_shrub_coverC), to = max(CasTet.tot$CasTet_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(CasTet.tot$graminoid_coverC), to = max(CasTet.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(CasTet.tot$sriC), to = max(CasTet.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(CasTet.tot$triC), to = max(CasTet.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(CasTet.tot$tcwsC), to = max(CasTet.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(CasTet.tot$tempjjaC), to = max(CasTet.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(CasTet.tot$precipjjaC), to = max(CasTet.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(CasTet.tot$tempcontC), to = max(CasTet.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(CasTet.tot$tempjjaC,0.05),quantile(CasTet.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.CasTet.data)
List of 36
 $ cov.dis             : num [1:398] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:398] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.dis         : num [1:398] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.dis             : num [1:398] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis             : num [1:398] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.dis            : num [1:398] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.dis       : num [1:398] 0.101 0.911 0.304 0.607 0.101 ...
 $ gramin_cov.dis      : num [1:398] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:398] -0.266 -0.266 -0.266 -0.41 -0.266 ...
 $ N_discrete          : int 398
 $ cov.cont            : num [1:16] 0.04 0.04 0.08 0.04 0.08 0.72 0.08 0.04 0.16 0.04 ...
 $ plotgroup.cont      : num [1:16] 30 30 30 38 43 49 49 49 49 49 ...
 $ tempjja.cont        : num [1:16] 0.262 0.262 0.367 0.569 1.061 ...
 $ sri.cont            : num [1:16] -0.314 -1.308 -0.87 0.754 -0.746 ...
 $ tri.cont            : num [1:16] 1.725 1.526 1.289 -0.803 1.523 ...
 $ tcws.cont           : num [1:16] 1.525 1.716 1.716 -0.101 0.67 ...
 $ shrub_cov.cont      : num [1:16] 1.417 0.405 1.518 -0.607 -0.101 ...
 $ gramin_cov.cont     : num [1:16] -0.195 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.cont         : num [1:16] -0.727 -0.959 -1.741 -0.674 -0.495 ...
 $ N_cont              : int 16
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -2.7 -2.68 -2.65 -2.63 -2.6 ...
 $ xhat_shrub_cover    : num [1:100] -1.21 -1.17 -1.12 -1.08 -1.03 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# EmpNig ----
shrub_gradient_jags.EmpNig.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = EmpNig.dis$cover,
  plotgroup.dis = EmpNig.dis$plotgroup.NUM,
  tempjja.dis = EmpNig.dis$tempjjaC,
  sri.dis = EmpNig.dis$sriC,
  tri.dis = EmpNig.dis$triC,
  tcws.dis = EmpNig.dis$tcwsC,
  shrub_cov.dis = EmpNig.dis$EmpNig_shrub_coverC,
  gramin_cov.dis = EmpNig.dis$graminoid_coverC,
  compet.dis = EmpNig.dis$competC,
  N_discrete = nrow(EmpNig.dis),
  
  # ...and continuous part of the data
  cov.cont = EmpNig.cont$cover,
  plotgroup.cont = EmpNig.cont$plotgroup.NUM,
  tempjja.cont = EmpNig.cont$tempjjaC,
  sri.cont = EmpNig.cont$sriC,
  tri.cont = EmpNig.cont$triC,
  tcws.cont = EmpNig.cont$tcwsC,
  shrub_cov.cont = EmpNig.cont$EmpNig_shrub_coverC,
  gramin_cov.cont = EmpNig.cont$graminoid_coverC,
  compet.cont = EmpNig.cont$competC,
  N_cont = nrow(EmpNig.cont),
  
  # plot group level predictors
  tempjja.tot = EmpNig.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = EmpNig.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = EmpNig.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(EmpNig.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(EmpNig.tot$competC), to = max(EmpNig.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(EmpNig.tot$EmpNig_shrub_coverC), to = max(EmpNig.tot$EmpNig_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(EmpNig.tot$graminoid_coverC), to = max(EmpNig.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(EmpNig.tot$sriC), to = max(EmpNig.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(EmpNig.tot$triC), to = max(EmpNig.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(EmpNig.tot$tcwsC), to = max(EmpNig.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(EmpNig.tot$tempjjaC), to = max(EmpNig.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(EmpNig.tot$precipjjaC), to = max(EmpNig.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(EmpNig.tot$tempcontC), to = max(EmpNig.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(EmpNig.tot$tempjjaC,0.05),quantile(EmpNig.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.EmpNig.data)
List of 36
 $ cov.dis             : num [1:229] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:229] 2 2 3 5 5 6 6 6 7 7 ...
 $ tempjja.dis         : num [1:229] -0.283 -0.288 -0.226 -0.42 -0.44 ...
 $ sri.dis             : num [1:229] 0.9453 -1.4348 -1.4755 0.7837 -0.0244 ...
 $ tri.dis             : num [1:229] -0.987 0.1646 0.0108 0.0788 0.2101 ...
 $ tcws.dis            : num [1:229] -1.935 -2.034 -0.366 -0.12 -0.466 ...
 $ shrub_cov.dis       : num [1:229] -0.985 -0.985 -0.985 -0.985 -0.985 ...
 $ gramin_cov.dis      : num [1:229] -0.582 -0.582 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:229] -0.37 -0.37 -0.37 -0.37 -0.37 ...
 $ N_discrete          : int 229
 $ cov.cont            : num [1:185] 0.52 0.84 0.6 0.64 0.52 0.16 0.16 0.64 0.16 0.52 ...
 $ plotgroup.cont      : num [1:185] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.cont        : num [1:185] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.cont            : num [1:185] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.cont            : num [1:185] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.cont           : num [1:185] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.cont      : num [1:185] -0.985 -0.985 -0.985 -0.745 -0.985 ...
 $ gramin_cov.cont     : num [1:185] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.cont         : num [1:185] -0.37 -0.37 -0.37 -0.515 -0.37 ...
 $ N_cont              : int 185
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -2.81 -2.78 -2.76 -2.73 -2.71 ...
 $ xhat_shrub_cover    : num [1:100] -0.985 -0.94 -0.895 -0.85 -0.806 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# PhyCae ----
shrub_gradient_jags.PhyCae.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = PhyCae.dis$cover,
  plotgroup.dis = PhyCae.dis$plotgroup.NUM,
  tempjja.dis = PhyCae.dis$tempjjaC,
  sri.dis = PhyCae.dis$sriC,
  tri.dis = PhyCae.dis$triC,
  tcws.dis = PhyCae.dis$tcwsC,
  shrub_cov.dis = PhyCae.dis$PhyCae_shrub_coverC,
  gramin_cov.dis = PhyCae.dis$graminoid_coverC,
  compet.dis = PhyCae.dis$competC,
  N_discrete = nrow(PhyCae.dis),
  
  # ...and continuous part of the data
  cov.cont = PhyCae.cont$cover,
  plotgroup.cont = PhyCae.cont$plotgroup.NUM,
  tempjja.cont = PhyCae.cont$tempjjaC,
  sri.cont = PhyCae.cont$sriC,
  tri.cont = PhyCae.cont$triC,
  tcws.cont = PhyCae.cont$tcwsC,
  shrub_cov.cont = PhyCae.cont$PhyCae_shrub_coverC,
  gramin_cov.cont = PhyCae.cont$graminoid_coverC,
  compet.cont = PhyCae.cont$competC,
  N_cont = nrow(PhyCae.cont),
  
  # plot group level predictors
  tempjja.tot = PhyCae.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = PhyCae.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = PhyCae.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(PhyCae.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(PhyCae.tot$competC), to = max(PhyCae.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(PhyCae.tot$PhyCae_shrub_coverC), to = max(PhyCae.tot$PhyCae_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(PhyCae.tot$graminoid_coverC), to = max(PhyCae.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(PhyCae.tot$sriC), to = max(PhyCae.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(PhyCae.tot$triC), to = max(PhyCae.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(PhyCae.tot$tcwsC), to = max(PhyCae.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(PhyCae.tot$tempjjaC), to = max(PhyCae.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(PhyCae.tot$precipjjaC), to = max(PhyCae.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(PhyCae.tot$tempcontC), to = max(PhyCae.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(PhyCae.tot$tempjjaC,0.05),quantile(PhyCae.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.PhyCae.data)
List of 36
 $ cov.dis             : num [1:404] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:404] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.dis         : num [1:404] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.dis             : num [1:404] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis             : num [1:404] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.dis            : num [1:404] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.dis       : num [1:404] 0.0921 0.8948 0.2928 0.5938 0.0921 ...
 $ gramin_cov.dis      : num [1:404] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:404] -0.118 -0.118 -0.118 -0.263 -0.118 ...
 $ N_discrete          : int 404
 $ cov.cont            : num [1:10] 0.04 0.08 0.08 0.12 0.08 0.04 0.04 0.12 0.44 0.12
 $ plotgroup.cont      : num [1:10] 9 11 14 17 24 30 36 51 51 69
 $ tempjja.cont        : num [1:10] 0.0508 0.7561 0.7023 1.0077 1.3121 ...
 $ sri.cont            : num [1:10] -0.7393 -0.0933 -0.2978 0.4817 0.075 ...
 $ tri.cont            : num [1:10] -1.116 -0.199 0.631 -0.24 0.115 ...
 $ tcws.cont           : num [1:10] 0.0921 1.162 -0.8479 0.7667 -0.3658 ...
 $ shrub_cov.cont      : num [1:10] -1.21224 2.19909 -0.40957 1.19576 -0.00824 ...
 $ gramin_cov.cont     : num [1:10] -0.38881 -0.00187 -0.19534 -0.19534 -0.38881 ...
 $ compet.cont         : num [1:10] -0.118 -1.419 -0.275 -0.768 -0.458 ...
 $ N_cont              : int 10
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -2.55 -2.53 -2.5 -2.48 -2.45 ...
 $ xhat_shrub_cover    : num [1:100] -1.21 -1.17 -1.12 -1.08 -1.03 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# RhoGro ----
shrub_gradient_jags.RhoGro.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = RhoGro.dis$cover,
  plotgroup.dis = RhoGro.dis$plotgroup.NUM,
  tempjja.dis = RhoGro.dis$tempjjaC,
  sri.dis = RhoGro.dis$sriC,
  tri.dis = RhoGro.dis$triC,
  tcws.dis = RhoGro.dis$tcwsC,
  shrub_cov.dis = RhoGro.dis$RhoGro_shrub_coverC,
  gramin_cov.dis = RhoGro.dis$graminoid_coverC,
  compet.dis = RhoGro.dis$competC,
  N_discrete = nrow(RhoGro.dis),
  
  # ...and continuous part of the data
  cov.cont = RhoGro.cont$cover,
  plotgroup.cont = RhoGro.cont$plotgroup.NUM,
  tempjja.cont = RhoGro.cont$tempjjaC,
  sri.cont = RhoGro.cont$sriC,
  tri.cont = RhoGro.cont$triC,
  tcws.cont = RhoGro.cont$tcwsC,
  shrub_cov.cont = RhoGro.cont$RhoGro_shrub_coverC,
  gramin_cov.cont = RhoGro.cont$graminoid_coverC,
  compet.cont = RhoGro.cont$competC,
  N_cont = nrow(RhoGro.cont),
  
  # plot group level predictors
  tempjja.tot = RhoGro.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = RhoGro.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = RhoGro.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(RhoGro.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(RhoGro.tot$competC), to = max(RhoGro.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(RhoGro.tot$RhoGro_shrub_coverC), to = max(RhoGro.tot$RhoGro_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(RhoGro.tot$graminoid_coverC), to = max(RhoGro.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(RhoGro.tot$sriC), to = max(RhoGro.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(RhoGro.tot$triC), to = max(RhoGro.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(RhoGro.tot$tcwsC), to = max(RhoGro.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(RhoGro.tot$tempjjaC), to = max(RhoGro.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(RhoGro.tot$precipjjaC), to = max(RhoGro.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(RhoGro.tot$tempcontC), to = max(RhoGro.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(RhoGro.tot$tempjjaC,0.05),quantile(RhoGro.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.RhoGro.data)
List of 36
 $ cov.dis             : num [1:325] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:325] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.dis         : num [1:325] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.dis             : num [1:325] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis             : num [1:325] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.dis            : num [1:325] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.dis       : num [1:325] 0.24 1.138 0.464 0.801 0.24 ...
 $ gramin_cov.dis      : num [1:325] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:325] -0.0764 -0.0764 -0.0764 -0.221 -0.0764 ...
 $ N_discrete          : int 325
 $ cov.cont            : num [1:89] 0.08 0.12 0.52 0.36 0.28 0.04 0.04 0.16 0.04 0.04 ...
 $ plotgroup.cont      : num [1:89] 5 11 20 20 20 20 20 20 24 24 ...
 $ tempjja.cont        : num [1:89] -0.42 0.756 0.374 0.426 0.426 ...
 $ sri.cont            : num [1:89] 0.8231 -0.9499 -0.0661 -0.0445 -2.5789 ...
 $ tri.cont            : num [1:89] 0.4531 -0.0842 1.311 1.4128 0.9228 ...
 $ tcws.cont           : num [1:89] 0.176 1.052 0.586 0.699 0.839 ...
 $ shrub_cov.cont      : num [1:89] 2.261 1.026 0.689 0.24 0.689 ...
 $ gramin_cov.cont     : num [1:89] 0.965 -0.582 -0.582 -0.582 -0.195 ...
 $ compet.cont         : num [1:89] -1.033 -0.74 -1.233 -0.961 -1.353 ...
 $ N_cont              : int 89
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -2.48 -2.45 -2.43 -2.4 -2.38 ...
 $ xhat_shrub_cover    : num [1:100] -1.22 -1.17 -1.13 -1.08 -1.04 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# RhoTom ----
shrub_gradient_jags.RhoTom.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = RhoTom.dis$cover,
  plotgroup.dis = RhoTom.dis$plotgroup.NUM,
  tempjja.dis = RhoTom.dis$tempjjaC,
  sri.dis = RhoTom.dis$sriC,
  tri.dis = RhoTom.dis$triC,
  tcws.dis = RhoTom.dis$tcwsC,
  shrub_cov.dis = RhoTom.dis$RhoTom_shrub_coverC,
  gramin_cov.dis = RhoTom.dis$graminoid_coverC,
  compet.dis = RhoTom.dis$competC,
  N_discrete = nrow(RhoTom.dis),
  
  # ...and continuous part of the data
  cov.cont = RhoTom.cont$cover,
  plotgroup.cont = RhoTom.cont$plotgroup.NUM,
  tempjja.cont = RhoTom.cont$tempjjaC,
  sri.cont = RhoTom.cont$sriC,
  tri.cont = RhoTom.cont$triC,
  tcws.cont = RhoTom.cont$tcwsC,
  shrub_cov.cont = RhoTom.cont$RhoTom_shrub_coverC,
  gramin_cov.cont = RhoTom.cont$graminoid_coverC,
  compet.cont = RhoTom.cont$competC,
  N_cont = nrow(RhoTom.cont),
  
  # plot group level predictors
  tempjja.tot = RhoTom.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = RhoTom.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = RhoTom.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(RhoTom.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(RhoTom.tot$competC), to = max(RhoTom.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(RhoTom.tot$RhoTom_shrub_coverC), to = max(RhoTom.tot$RhoTom_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(RhoTom.tot$graminoid_coverC), to = max(RhoTom.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(RhoTom.tot$sriC), to = max(RhoTom.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(RhoTom.tot$triC), to = max(RhoTom.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(RhoTom.tot$tcwsC), to = max(RhoTom.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(RhoTom.tot$tempjjaC), to = max(RhoTom.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(RhoTom.tot$precipjjaC), to = max(RhoTom.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(RhoTom.tot$tempcontC), to = max(RhoTom.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(RhoTom.tot$tempjjaC,0.05),quantile(RhoTom.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.RhoTom.data)
List of 36
 $ cov.dis             : num [1:401] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:401] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.dis         : num [1:401] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.dis             : num [1:401] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis             : num [1:401] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.dis            : num [1:401] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.dis       : num [1:401] 0.0983 0.9077 0.3006 0.6042 0.0983 ...
 $ gramin_cov.dis      : num [1:401] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:401] -0.0764 -0.0764 -0.0764 -0.221 -0.0764 ...
 $ N_discrete          : int 401
 $ cov.cont            : num [1:13] 0.12 0.2 0.12 0.4 0.2 0.2 0.2 0.24 0.04 0.2 ...
 $ plotgroup.cont      : num [1:13] 11 11 12 30 30 36 39 39 42 43 ...
 $ tempjja.cont        : num [1:13] 0.756 0.756 0.542 0.148 0.262 ...
 $ sri.cont            : num [1:13] -0.95 0.723 -0.185 0.633 -1.308 ...
 $ tri.cont            : num [1:13] -0.0842 -0.2235 -0.422 1.6901 1.5259 ...
 $ tcws.cont           : num [1:13] 1.05 1.05 0.74 1.72 1.72 ...
 $ shrub_cov.cont      : num [1:13] 0.80655 0.70536 1.21129 0.30062 -0.00293 ...
 $ gramin_cov.cont     : num [1:13] -0.582 -0.582 1.546 -0.582 -0.389 ...
 $ compet.cont         : num [1:13] -0.74 -0.51 -0.378 -0.565 -0.716 ...
 $ N_cont              : int 13
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -2.48 -2.45 -2.43 -2.4 -2.38 ...
 $ xhat_shrub_cover    : num [1:100] -1.22 -1.17 -1.13 -1.08 -1.03 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# SalArc ----
shrub_gradient_jags.SalArc.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = SalArc.dis$cover,
  plotgroup.dis = SalArc.dis$plotgroup.NUM,
  tempjja.dis = SalArc.dis$tempjjaC,
  sri.dis = SalArc.dis$sriC,
  tri.dis = SalArc.dis$triC,
  tcws.dis = SalArc.dis$tcwsC,
  shrub_cov.dis = SalArc.dis$SalArc_shrub_coverC,
  gramin_cov.dis = SalArc.dis$graminoid_coverC,
  compet.dis = SalArc.dis$competC,
  N_discrete = nrow(SalArc.dis),
  
  # ...and continuous part of the data
  cov.cont = SalArc.cont$cover,
  plotgroup.cont = SalArc.cont$plotgroup.NUM,
  tempjja.cont = SalArc.cont$tempjjaC,
  sri.cont = SalArc.cont$sriC,
  tri.cont = SalArc.cont$triC,
  tcws.cont = SalArc.cont$tcwsC,
  shrub_cov.cont = SalArc.cont$SalArc_shrub_coverC,
  gramin_cov.cont = SalArc.cont$graminoid_coverC,
  compet.cont = SalArc.cont$competC,
  N_cont = nrow(SalArc.cont),
  
  # plot group level predictors
  tempjja.tot = SalArc.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = SalArc.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = SalArc.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(SalArc.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(SalArc.tot$competC), to = max(SalArc.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(SalArc.tot$SalArc_shrub_coverC), to = max(SalArc.tot$SalArc_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(SalArc.tot$graminoid_coverC), to = max(SalArc.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(SalArc.tot$sriC), to = max(SalArc.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(SalArc.tot$triC), to = max(SalArc.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(SalArc.tot$tcwsC), to = max(SalArc.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(SalArc.tot$tempjjaC), to = max(SalArc.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(SalArc.tot$precipjjaC), to = max(SalArc.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(SalArc.tot$tempcontC), to = max(SalArc.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(SalArc.tot$tempjjaC,0.05),quantile(SalArc.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.SalArc.data)
List of 36
 $ cov.dis             : num [1:401] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:401] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.dis         : num [1:401] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.dis             : num [1:401] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis             : num [1:401] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.dis            : num [1:401] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.dis       : num [1:401] 0.09 0.894 0.291 0.592 0.09 ...
 $ gramin_cov.dis      : num [1:401] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:401] 1.76 1.76 1.76 1.61 1.76 ...
 $ N_discrete          : int 401
 $ cov.cont            : num [1:13] 0.04 0.04 0.08 0.04 0.04 0.04 0.04 0.2 0.08 0.04 ...
 $ plotgroup.cont      : num [1:13] 4 4 5 9 16 17 18 30 43 45 ...
 $ tempjja.cont        : num [1:13] -0.3953 -0.3953 -0.4199 0.0508 1.3027 ...
 $ sri.cont            : num [1:13] -1.344 -2.825 0.823 0.14 0.305 ...
 $ tri.cont            : num [1:13] 1.583 1.364 0.453 -0.511 -0.944 ...
 $ tcws.cont           : num [1:13] 0.248 0.163 0.176 0.182 -2.3 ...
 $ shrub_cov.cont      : num [1:13] 0.291 0.09 1.898 -0.111 -0.714 ...
 $ gramin_cov.cont     : num [1:13] -0.582 -0.582 0.965 0.772 -0.582 ...
 $ compet.cont         : num [1:13] 1.758 1.18 0.948 1.758 1.397 ...
 $ N_cont              : int 13
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -0.37 -0.349 -0.327 -0.306 -0.284 ...
 $ xhat_shrub_cover    : num [1:100] -1.22 -1.17 -1.12 -1.08 -1.03 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# SalGla ----
shrub_gradient_jags.SalGla.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = SalGla.dis$cover,
  plotgroup.dis = SalGla.dis$plotgroup.NUM,
  tempjja.dis = SalGla.dis$tempjjaC,
  sri.dis = SalGla.dis$sriC,
  tri.dis = SalGla.dis$triC,
  tcws.dis = SalGla.dis$tcwsC,
  shrub_cov.dis = SalGla.dis$SalGla_shrub_coverC,
  gramin_cov.dis = SalGla.dis$graminoid_coverC,
  compet.dis = SalGla.dis$competC,
  N_discrete = nrow(SalGla.dis),
  
  # ...and continuous part of the data
  cov.cont = SalGla.cont$cover,
  plotgroup.cont = SalGla.cont$plotgroup.NUM,
  tempjja.cont = SalGla.cont$tempjjaC,
  sri.cont = SalGla.cont$sriC,
  tri.cont = SalGla.cont$triC,
  tcws.cont = SalGla.cont$tcwsC,
  shrub_cov.cont = SalGla.cont$SalGla_shrub_coverC,
  gramin_cov.cont = SalGla.cont$graminoid_coverC,
  compet.cont = SalGla.cont$competC,
  N_cont = nrow(SalGla.cont),
  
  # plot group level predictors
  tempjja.tot = SalGla.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = SalGla.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = SalGla.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(SalGla.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(SalGla.tot$competC), to = max(SalGla.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(SalGla.tot$SalGla_shrub_coverC), to = max(SalGla.tot$SalGla_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(SalGla.tot$graminoid_coverC), to = max(SalGla.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(SalGla.tot$sriC), to = max(SalGla.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(SalGla.tot$triC), to = max(SalGla.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(SalGla.tot$tcwsC), to = max(SalGla.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(SalGla.tot$tempjjaC), to = max(SalGla.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(SalGla.tot$precipjjaC), to = max(SalGla.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(SalGla.tot$tempcontC), to = max(SalGla.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(SalGla.tot$tempjjaC,0.05),quantile(SalGla.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.SalGla.data)
List of 36
 $ cov.dis             : num [1:289] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:289] 1 1 1 1 1 1 2 2 2 2 ...
 $ tempjja.dis         : num [1:289] -0.321 -0.321 -0.321 -0.345 -0.345 ...
 $ sri.dis             : num [1:289] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis             : num [1:289] -0.255 -0.314 -0.307 -0.274 -0.18 ...
 $ tcws.dis            : num [1:289] -0.4925 -0.0586 -0.0586 -0.0999 -0.6658 ...
 $ shrub_cov.dis       : num [1:289] 0.291 1.163 0.509 0.836 0.291 ...
 $ gramin_cov.dis      : num [1:289] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:289] 1.76 1.76 1.76 1.61 1.76 ...
 $ N_discrete          : int 289
 $ cov.cont            : num [1:125] 0.32 0.12 0.2 0.08 0.44 0.08 0.04 0.12 0.04 0.04 ...
 $ plotgroup.cont      : num [1:125] 2 2 4 4 6 8 11 11 12 14 ...
 $ tempjja.cont        : num [1:125] -0.288 -0.288 -0.395 -0.395 -0.4 ...
 $ sri.cont            : num [1:125] -1.562 -0.758 0.646 -2.68 -0.409 ...
 $ tri.cont            : num [1:125] 0.000194 0.116122 -0.957191 1.458727 0.141645 ...
 $ tcws.cont           : num [1:125] -1.542 -1.229 0.431 0.163 -0.848 ...
 $ shrub_cov.cont      : num [1:125] -0.69 0.291 0.836 0.727 0.4 ...
 $ gramin_cov.cont     : num [1:125] -0.582 -0.582 -0.195 -0.582 -0.582 ...
 $ compet.cont         : num [1:125] 1.76 1.76 1.76 1.76 1.76 ...
 $ N_cont              : int 125
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -0.37 -0.349 -0.327 -0.306 -0.284 ...
 $ xhat_shrub_cover    : num [1:100] -1.126 -1.083 -1.04 -0.997 -0.954 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# VacUli ----
shrub_gradient_jags.VacUli.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = VacUli.dis$cover,
  plotgroup.dis = VacUli.dis$plotgroup.NUM,
  tempjja.dis = VacUli.dis$tempjjaC,
  sri.dis = VacUli.dis$sriC,
  tri.dis = VacUli.dis$triC,
  tcws.dis = VacUli.dis$tcwsC,
  shrub_cov.dis = VacUli.dis$VacUli_shrub_coverC,
  gramin_cov.dis = VacUli.dis$graminoid_coverC,
  compet.dis = VacUli.dis$competC,
  N_discrete = nrow(VacUli.dis),
  
  # ...and continuous part of the data
  cov.cont = VacUli.cont$cover,
  plotgroup.cont = VacUli.cont$plotgroup.NUM,
  tempjja.cont = VacUli.cont$tempjjaC,
  sri.cont = VacUli.cont$sriC,
  tri.cont = VacUli.cont$triC,
  tcws.cont = VacUli.cont$tcwsC,
  shrub_cov.cont = VacUli.cont$VacUli_shrub_coverC,
  gramin_cov.cont = VacUli.cont$graminoid_coverC,
  compet.cont = VacUli.cont$competC,
  N_cont = nrow(VacUli.cont),
  
  # plot group level predictors
  tempjja.tot = VacUli.tot %>% group_by(plotgroup.NUM) %>% summarise(tempjja.tot = mean(tempjjaC)) %>% pull(tempjja.tot), # one value per tXpg
  tempcont.tot = VacUli.tot %>% group_by(plotgroup.NUM) %>% summarise(tempcont.tot = mean(tempcontC)) %>% pull(tempcont.tot),
  precipjja.tot = VacUli.tot %>% group_by(plotgroup.NUM) %>% summarise(precipjja.tot = mean(precipjjaC)) %>% pull(precipjja.tot),
  N_plotgroups = length(unique(VacUli.tot$site_alt_plotgroup_id)),
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(VacUli.tot$competC), to = max(VacUli.tot$competC), length.out = 100),
  xhat_shrub_cover = seq(from = min(VacUli.tot$VacUli_shrub_coverC), to = max(VacUli.tot$VacUli_shrub_coverC), length.out = 100),
  xhat_graminoid_cover = seq(from = min(VacUli.tot$graminoid_coverC), to = max(VacUli.tot$graminoid_coverC), length.out = 100),
  xhat_sri = seq(from = min(VacUli.tot$sriC), to = max(VacUli.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(VacUli.tot$triC), to = max(VacUli.tot$triC), length.out = 100),
  xhat_tcws = seq(from = min(VacUli.tot$tcwsC), to = max(VacUli.tot$tcwsC), length.out = 100),
  xhat_tempjja = seq(from = min(VacUli.tot$tempjjaC), to = max(VacUli.tot$tempjjaC), length.out = 100),
  xhat_precipjja = seq(from = min(VacUli.tot$precipjjaC), to = max(VacUli.tot$precipjjaC), length.out = 100),
  xhat_tempcont = seq(from = min(VacUli.tot$tempcontC), to = max(VacUli.tot$tempcontC), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tcws2 = as.numeric(c(quantile(VacUli.tot$tempjjaC,0.05),quantile(VacUli.tot$tempjjaC,0.95))), 
  Nxhat2 = 2
)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)
str(shrub_gradient_jags.VacUli.data)
List of 36
 $ cov.dis             : num [1:309] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis       : num [1:309] 1 1 1 1 2 2 2 2 2 2 ...
 $ tempjja.dis         : num [1:309] -0.321 -0.321 -0.321 -0.345 -0.283 ...
 $ sri.dis             : num [1:309] 0.51 0.829 1.034 0.573 0.945 ...
 $ tri.dis             : num [1:309] -0.255 -0.314 -0.307 -0.18 -0.987 ...
 $ tcws.dis            : num [1:309] -0.4925 -0.0586 -0.0586 -0.6658 -1.935 ...
 $ shrub_cov.dis       : num [1:309] 0.243 1.121 0.462 0.243 -1.185 ...
 $ gramin_cov.dis      : num [1:309] -0.582 -0.389 -0.582 -0.582 -0.582 ...
 $ compet.dis          : num [1:309] 1.44 1.44 1.44 1.44 -0.37 ...
 $ N_discrete          : int 309
 $ cov.cont            : num [1:105] 0.08 0.04 0.24 0.28 0.08 0.32 0.36 0.28 0.08 0.16 ...
 $ plotgroup.cont      : num [1:105] 1 1 3 3 4 4 5 10 10 11 ...
 $ tempjja.cont        : num [1:105] -0.345 -0.345 -0.226 -0.226 -0.395 ...
 $ sri.cont            : num [1:105] 0.37 0.688 -0.207 -1.955 -0.556 ...
 $ tri.cont            : num [1:105] -0.274 0.19 0.149 0.385 1.362 ...
 $ tcws.cont           : num [1:105] -0.0999 -0.6658 -0.2434 -0.2434 0.1631 ...
 $ shrub_cov.cont      : num [1:105] 0.572 -0.7454 0.1329 0.6818 0.0231 ...
 $ gramin_cov.cont     : num [1:105] -0.582 -0.582 -0.582 -0.582 -0.582 ...
 $ compet.cont         : num [1:105] 1.44 1.44 1.44 1.44 1.44 ...
 $ N_cont              : int 105
 $ tempjja.tot         : num [1:69] -0.333 -0.286 -0.222 -0.396 -0.426 ...
 $ tempcont.tot        : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot       : num [1:69] 0.711 0.869 1.058 0.629 0.59 ...
 $ N_plotgroups        : int 69
 $ xhat_compet         : num [1:100] -0.999 -0.974 -0.95 -0.925 -0.9 ...
 $ xhat_shrub_cover    : num [1:100] -1.185 -1.135 -1.085 -1.035 -0.985 ...
 $ xhat_graminoid_cover: num [1:100] -0.582 -0.504 -0.426 -0.348 -0.27 ...
 $ xhat_sri            : num [1:100] -3.11 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri            : num [1:100] -1.72 -1.66 -1.6 -1.54 -1.48 ...
 $ xhat_tcws           : num [1:100] -3.08 -3.03 -2.97 -2.92 -2.87 ...
 $ xhat_tempjja        : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja      : num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont       : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat               : num 100
 $ xhat_tcws2          : num [1:2] -2.01 1.31
 $ Nxhat2              : num 2
# # save model input data
save(list = c("shrub_gradient_jags.BetNan.data",
              "shrub_gradient_jags.CasTet.data",
              "shrub_gradient_jags.EmpNig.data",
              "shrub_gradient_jags.PhyCae.data",
              "shrub_gradient_jags.RhoGro.data",
              "shrub_gradient_jags.RhoTom.data",
              "shrub_gradient_jags.SalArc.data",
              "shrub_gradient_jags.SalGla.data",
              "shrub_gradient_jags.VacUli.data"),
     file = file.path("..", "data", "processed", "model_input_data_tcws", "shrub_gradient_jags.speciesdata.Rdata"))

> specifying model

write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.shrub_cov ~ dnorm(0, 0.0001)
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      b.tempXtcws2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.shrub_cov * shrub_cov.dis[i] + 
                        b.gramin_cov * gramin_cov.dis[i] + 
                        b.tempXtcws * tempjja.dis[i] * tcws.dis[i] +       # for interaction
                        b.tempXtcws2 * (tempjja.dis[i]^2) * tcws.dis[i] +  # for interaction
                        b.tcws * tcws.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.shrub_cov * shrub_cov.cont[j] +
                        b.gramin_cov * gramin_cov.cont[j] +
                        b.tempXtcws * tempjja.cont[j] * tcws.cont[j] +       # for interaction
                        b.tempXtcws2 * (tempjja.cont[j]^2) * tcws.cont[j] +  # for interaction
                        b.tcws * tcws.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] + 
                    b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_shrub_cover[m] <- intercept + b.shrub_cov * xhat_shrub_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] +
                                      b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
          }
        }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.spec.jags"))

Specify the parameters to be monitored:

params <- c("intercept",
            "b.tempjja.x", "b.tempjja.x2",
            "b.tempcont.x", "b.tempcont.x2",
            "b.precipjja.x", "b.precipjja.x2",
            "b.compet",
            "b.shrub_cov", 
            "b.gramin_cov",
            "b.sri",
            "b.tri",
            "b.tcws",
            "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
            "sigma.plotgroup",
            "phi",
            "phat_compet", "phat_shrub_cover", "phat_graminoid_cover", 
            "phat_sri", "phat_tcws", "phat_tri", 
            "phat_tempjja", "phat_tempcont", "phat_precipjja", 
            "phat_tempXmoist")

> run & evaluate model


Betula nana

# run model
model_out.shrub_gradient.BetNan <- jags(shrub_gradient_jags.BetNan.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 

# plot(model_out.shrub_gradient.BetNan) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.BetNan <- model_out.shrub_gradient.BetNan$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.BetNan),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.BetNan <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.BetNan$BUGSoutput$sims.list)-4)){
  ci_90.BetNan[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.BetNan$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.BetNan[param, 3] <- names(data.frame(model_out.shrub_gradient.BetNan$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.BetNan <- coeff.shrub_gradient.BetNan %>% 
  left_join(ci_90.BetNan, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat)

save(coeff.shrub_gradient.BetNan, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_BetNan.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_BetNan.Rdata"))
print(coeff.shrub_gradient.BetNan)
(effect_size_plot.BetNan <- model_plot_sig_function(coeff.shrub_gradient.BetNan, title_string = "Betula nana", plot_width = 12.5))

  • positive relationship with more conservative communities, negative response to graminoid cover (sig.)
  • unimodal relationship with temperature variability (m.s.)


As none of the quadratic terms for climatic variables were significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.shrub_cov ~ dnorm(0, 0.0001)
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      # b.tempXtcws2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.shrub_cov * shrub_cov.dis[i] + 
                        b.gramin_cov * gramin_cov.dis[i] + 
                        b.tempXtcws * tempjja.dis[i] * tcws.dis[i] +       # for interaction
                        # b.tempXtcws2 * (tempjja.dis[i]^2) * tcws.dis[i] +  # for interaction
                        b.tcws * tcws.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.shrub_cov * shrub_cov.cont[j] +
                        b.gramin_cov * gramin_cov.cont[j] +
                        b.tempXtcws * tempjja.cont[j] * tcws.cont[j] +       # for interaction
                        # b.tempXtcws2 * (tempjja.cont[j]^2) * tcws.cont[j] +  # for interaction
                        b.tcws * tcws.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_shrub_cover[m] <- intercept + b.shrub_cov * xhat_shrub_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] # + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] # + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      # b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] # +
                                      # b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
          }
        }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.BetNan2.jags"))

# specify new set of parameters to be monitored
params_BetNan2 <- c("intercept",
                    "b.tempjja.x", # "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.shrub_cov",
                    "b.gramin_cov",
                    "b.sri",
                    "b.tri",
                    "b.tcws",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_shrub_cover", "phat_graminoid_cover", 
                    "phat_sri", "phat_tri", "phat_tcws", 
                    "phat_tempjja", "phat_tempcont", "phat_precipjja",
                    "phat_tempXmoist")

model_out.shrub_gradient.BetNan2 <- jags(shrub_gradient_jags.BetNan.data,   # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_BetNan2,                     # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.BetNan2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.BetNan2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.BetNan2 <- model_out.shrub_gradient.BetNan2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.BetNan2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.BetNan2$BUGSoutput$sims.list)-4)){
  ci_90.BetNan2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.BetNan2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.BetNan2[param, 3] <- names(data.frame(model_out.shrub_gradient.BetNan2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.BetNan2 <- coeff.shrub_gradient.BetNan2 %>% 
  left_join(ci_90.BetNan2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.BetNan2, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_BetNan2.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_BetNan2.Rdata"))

# effect size plot
(effect_size_plot.BetNan2 <- model_plot_sig_function(coeff.shrub_gradient.BetNan2, title_string = "Betula nana", plot_width = 9.5))

  • positive response to temperature variability and more conservative communities, negative response to graminoid cover (sig.)
  • slightly positive relationship with topographic wetness (n.s.)


Cassiope tetragona

model_out.shrub_gradient.CasTet <- jags(shrub_gradient_jags.CasTet.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.CasTet) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.CasTet <- model_out.shrub_gradient.CasTet$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.CasTet),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.CasTet <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.CasTet$BUGSoutput$sims.list)-4)){
  ci_90.CasTet[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.CasTet$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.CasTet[param, 3] <- names(data.frame(model_out.shrub_gradient.CasTet$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.CasTet <- coeff.shrub_gradient.CasTet %>% 
  left_join(ci_90.CasTet, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat)

print(coeff.shrub_gradient.CasTet)

save(coeff.shrub_gradient.CasTet, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_CasTet.Rdata"))
  • not converging: large R-hat values (~ 1.3) (only 16 non-zero values across plot groups)


Empetrum nigrum

model_out.shrub_gradient.EmpNig <- jags(shrub_gradient_jags.EmpNig.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.EmpNig) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.EmpNig <- model_out.shrub_gradient.EmpNig$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.EmpNig),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.EmpNig <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.EmpNig$BUGSoutput$sims.list)-4)){
  ci_90.EmpNig[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.EmpNig$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.EmpNig[param, 3] <- names(data.frame(model_out.shrub_gradient.EmpNig$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.EmpNig <- coeff.shrub_gradient.EmpNig %>% 
  left_join(ci_90.EmpNig, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.EmpNig, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_EmpNig.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_EmpNig.Rdata"))

# effect size plot
(effect_size_plot.EmpNig <- model_plot_marg_function(coeff.shrub_gradient.EmpNig, title_string = "Empetrum nigrum", plot_width = 12.5))

  • positive linear relationship to summer precipitation and TC wetness (sig.)


As none of the quadratic terms for climatic variables were significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.shrub_cov ~ dnorm(0, 0.0001)
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      # b.tempXtcws2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.shrub_cov * shrub_cov.dis[i] + 
                        b.gramin_cov * gramin_cov.dis[i] + 
                        b.tempXtcws * tempjja.dis[i] * tcws.dis[i] +       # for interaction
                        # b.tempXtcws2 * (tempjja.dis[i]^2) * tcws.dis[i] +  # for interaction
                        b.tcws * tcws.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.shrub_cov * shrub_cov.cont[j] +
                        b.gramin_cov * gramin_cov.cont[j] +
                        b.tempXtcws * tempjja.cont[j] * tcws.cont[j] +       # for interaction
                        # b.tempXtcws2 * (tempjja.cont[j]^2) * tcws.cont[j] +  # for interaction
                        b.tcws * tcws.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_shrub_cover[m] <- intercept + b.shrub_cov * xhat_shrub_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] # + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] # + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      # b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] # +
                                      # b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
          }
        }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.EmpNig2.jags"))

# specify new set of parameters to be monitored
params_EmpNig2 <- c("intercept",
                    "b.tempjja.x", # "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.shrub_cov",
                    "b.gramin_cov",
                    "b.sri",
                    "b.tri",
                    "b.tcws",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_shrub_cover", "phat_graminoid_cover", 
                    "phat_sri", "phat_tri", "phat_tcws", 
                    "phat_tempjja", "phat_tempcont", "phat_precipjja",
                    "phat_tempXmoist")

model_out.shrub_gradient.EmpNig2 <- jags(shrub_gradient_jags.EmpNig.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_EmpNig2,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.EmpNig2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.EmpNig2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.EmpNig2 <- model_out.shrub_gradient.EmpNig2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.EmpNig2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.EmpNig2$BUGSoutput$sims.list)-4)){
  ci_90.EmpNig2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.EmpNig2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.EmpNig2[param, 3] <- names(data.frame(model_out.shrub_gradient.EmpNig2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.EmpNig2 <- coeff.shrub_gradient.EmpNig2 %>% 
  left_join(ci_90.EmpNig2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.EmpNig2, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_EmpNig2.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_EmpNig2.Rdata"))

# effect size plot
(effect_size_plot.EmpNig2 <- model_plot_sig_function(coeff.shrub_gradient.EmpNig2, title_string = "Empetrum nigrum", plot_width = 9.5))

  • negative response to temperature variability, positive relationship with precipitation (linear) and TCwetness (sig.)
  • slightly negative response to graminoid cover (n.s.)


Phyllodoce caerulea

model_out.shrub_gradient.PhyCae <- jags(shrub_gradient_jags.PhyCae.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.PhyCae) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.PhyCae <- model_out.shrub_gradient.PhyCae$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.PhyCae),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.PhyCae <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.PhyCae$BUGSoutput$sims.list)-4)){
  ci_90.PhyCae[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.PhyCae$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.PhyCae[param, 3] <- names(data.frame(model_out.shrub_gradient.PhyCae$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.PhyCae <- coeff.shrub_gradient.PhyCae %>% 
  left_join(ci_90.PhyCae, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.PhyCae, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_PhyCae.Rdata"))
  • not converged well relatively large R-hat values (~ 1.02) (only 10 non-zero values across plot groups)


Rhododendron groenlandicum

model_out.shrub_gradient.RhoGro <- jags(shrub_gradient_jags.RhoGro.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.RhoGro) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.RhoGro <- model_out.shrub_gradient.RhoGro$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.RhoGro),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.RhoGro <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.RhoGro$BUGSoutput$sims.list)-4)){
  ci_90.RhoGro[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.RhoGro$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.RhoGro[param, 3] <- names(data.frame(model_out.shrub_gradient.RhoGro$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.RhoGro <- coeff.shrub_gradient.RhoGro %>% 
  left_join(ci_90.RhoGro, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.RhoGro, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_RhoGro.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_RhoGro.Rdata"))

# effect size plot
(effect_size_plot.RhoGro <- model_plot_marg_function(coeff.shrub_gradient.RhoGro, title_string = "Rhododendron groenlandicum", plot_width = 12.5))

  • negative response to graminoid cover (m.s.)
  • slightly positive response to temperature variability, solar radiation, terrain heterogeneity, TC wetness; slightly unimodal response to summer temperature (n.s.)


As the quadratic terms for climatic variables were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.shrub_cov ~ dnorm(0, 0.0001)
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      b.tempXtcws2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.shrub_cov * shrub_cov.dis[i] + 
                        b.gramin_cov * gramin_cov.dis[i] + 
                        b.tempXtcws * tempjja.dis[i] * tcws.dis[i] +       # for interaction
                        # b.tempXtcws2 * (tempjja.dis[i]^2) * tcws.dis[i] +  # for interaction
                        b.tcws * tcws.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.shrub_cov * shrub_cov.cont[j] +
                        b.gramin_cov * gramin_cov.cont[j] +
                        b.tempXtcws * tempjja.cont[j] * tcws.cont[j] +       # for interaction
                        # b.tempXtcws2 * (tempjja.cont[j]^2) * tcws.cont[j] +  # for interaction
                        b.tcws * tcws.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_shrub_cover[m] <- intercept + b.shrub_cov * xhat_shrub_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] # + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] # + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      # b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] # +
                                      # b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
          }
        }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.RhoGro2.jags"))

# specify new set of parameters to be monitored
params_RhoGro2 <- c("intercept",
                    "b.tempjja.x", # "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.shrub_cov",
                    "b.gramin_cov",
                    "b.sri",
                    "b.tri",
                    "b.tcws",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", 
                    "phat_shrub_cover", "phat_graminoid_cover", 
                    "phat_sri", "phat_tri", "phat_tcws", 
                    "phat_tempjja", "phat_tempcont", "phat_precipjja",
                    "phat_tempXmoist")

model_out.shrub_gradient.RhoGro2 <- jags(shrub_gradient_jags.RhoGro.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_RhoGro2,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.RhoGro2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.RhoGro2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.RhoGro2 <- model_out.shrub_gradient.RhoGro2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.RhoGro),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.RhoGro2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.RhoGro2$BUGSoutput$sims.list)-4)){
  ci_90.RhoGro2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.RhoGro2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.RhoGro2[param, 3] <- names(data.frame(model_out.shrub_gradient.RhoGro2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.RhoGro2 <- coeff.shrub_gradient.RhoGro2 %>% 
  left_join(ci_90.RhoGro2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.RhoGro2, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_RhoGro2.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_RhoGro2.Rdata"))

# effect size plot
(effect_size_plot.RhoGro2 <- model_plot_marg_function(coeff.shrub_gradient.RhoGro2, title_string = "Rhododendron groenlandicum", plot_width = 9.5))

  • positive relationship with TCwetness (sig.), positive relationship with temperature variability, negative with graminoid cover (m.s.)
  • negative relationship with precipitation (linear) (n.s.)


Rhododendron tomentosum

model_out.shrub_gradient.RhoTom <- jags(shrub_gradient_jags.RhoTom.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.RhoTom) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.RhoTom <- model_out.shrub_gradient.RhoTom$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.RhoTom),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.RhoTom <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.RhoTom$BUGSoutput$sims.list)-4)){
  ci_90.RhoTom[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.RhoTom$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.RhoTom[param, 3] <- names(data.frame(model_out.shrub_gradient.RhoTom$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.RhoTom <- coeff.shrub_gradient.RhoTom %>% 
  left_join(ci_90.RhoTom, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.RhoTom, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_RhoTom.Rdata"))
  • not converging: really large R-hat values (~ 2.7), large variation in parameter estimates (only 13 non-zero values)


Salix arctophila

model_out.shrub_gradient.SalArc <- jags(shrub_gradient_jags.SalArc.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.SalArc) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.SalArc <- model_out.shrub_gradient.SalArc$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.SalArc),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.SalArc <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.SalArc$BUGSoutput$sims.list)-4)){
  ci_90.SalArc[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalArc$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.SalArc[param, 3] <- names(data.frame(model_out.shrub_gradient.SalArc$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.SalArc <- coeff.shrub_gradient.SalArc %>% 
  left_join(ci_90.SalArc, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# R-hats look okay => check traceplots
# traceplot(coeff.shrub_gradient.SalArc)

save(coeff.shrub_gradient.SalArc, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_SalArc.Rdata"))
  • not converging well: relatively large R-hat values (< 1.04), and quite some variation in trace plots, especially for climatic parameters (only 13 non-zero values across plot groups)


Salix glauca

model_out.shrub_gradient.SalGla <- jags(shrub_gradient_jags.SalGla.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.SalGla) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.SalGla <- model_out.shrub_gradient.SalGla$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.SalGla),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.SalGla <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list)-4)){
  ci_90.SalGla[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.SalGla[param, 3] <- names(data.frame(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.SalGla <- coeff.shrub_gradient.SalGla %>% 
  left_join(ci_90.SalGla, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.SalGla, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_SalGla.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_SalGla.Rdata"))

# effect size plot
(effect_size_plot.SalGla <- model_plot_marg_function(coeff.shrub_gradient.SalGla, title_string = "Salix glauca", plot_width = 12.5))

  • positive relationship with less acquisitive communities (sig.), other shrub cover and temperature variability (m.s.)
  • slightly negative response to summer temperature (n.s.)


As the quadratic terms for summer temperature, temperature variability and summer precipitation were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{

    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.shrub_cov ~ dnorm(0, 0.0001)
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      # b.tempXtcws2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.shrub_cov * shrub_cov.dis[i] + 
                        b.gramin_cov * gramin_cov.dis[i] + 
                        b.tempXtcws * tempjja.dis[i] * tcws.dis[i] +       # for interaction
                        # b.tempXtcws2 * (tempjja.dis[i]^2) * tcws.dis[i] +  # for interaction
                        b.tcws * tcws.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.shrub_cov * shrub_cov.cont[j] +
                        b.gramin_cov * gramin_cov.cont[j] +
                        b.tempXtcws * tempjja.cont[j] * tcws.cont[j] +       # for interaction
                        # b.tempXtcws2 * (tempjja.cont[j]^2) * tcws.cont[j] +  # for interaction
                        b.tcws * tcws.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_shrub_cover[m] <- intercept + b.shrub_cov * xhat_shrub_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] # + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] # + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      # b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] # +
                                      # b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
          }
        }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.SalGla2.jags"))

# specify new set of parameters to be monitored
params_SalGla2 <- c("intercept",
                    "b.tempjja.x", # "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.shrub_cov",
                    "b.gramin_cov",
                    "b.sri",
                    "b.tri",
                    "b.tcws",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_shrub_cover", "phat_graminoid_cover", 
                    "phat_sri", "phat_tri", "phat_tcws", 
                    "phat_tempjja", "phat_tempcont", "phat_precipjja",
                    "phat_tempXmoist")

model_out.shrub_gradient.SalGla2 <- jags(shrub_gradient_jags.SalGla.data,   # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_SalGla2,                     # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.SalGla2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.SalGla2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.SalGla2 <- model_out.shrub_gradient.SalGla2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.SalGla2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list)-4)){
  ci_90.SalGla2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.SalGla2[param, 3] <- names(data.frame(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.SalGla2 <- coeff.shrub_gradient.SalGla2 %>% 
  left_join(ci_90.SalGla2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.SalGla2, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_SalGla2.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_SalGla2.Rdata"))

# effect size plot
(effect_size_plot.SalGla2 <- model_plot_sig_function(coeff.shrub_gradient.SalGla2, title_string = "Salix glauca", plot_width = 9.5))

  • positive relationship with conservative communities, temperature variability (linear) (sig.)
  • slightly positive relationship with other shrub cover and TCwetness (n.s.)


Vaccinium uliginosum

model_out.shrub_gradient.VacUli <- jags(shrub_gradient_jags.VacUli.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.VacUli) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.VacUli <- model_out.shrub_gradient.VacUli$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.VacUli),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.VacUli <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.VacUli$BUGSoutput$sims.list)-4)){
  ci_90.VacUli[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.VacUli$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.VacUli[param, 3] <- names(data.frame(model_out.shrub_gradient.VacUli$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.VacUli <- coeff.shrub_gradient.VacUli %>% 
  left_join(ci_90.VacUli, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.VacUli, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_VacUli.Rdata"))
# load(file.path("..", "data", "processed", "model_outputs", "species_tcws", "first_runs_converged", "model_output_VacUli.Rdata"))

# effect size plot
(effect_size_plot.VacUli <- model_plot_sig_function(coeff.shrub_gradient.VacUli, title_string = "Vaccinium uliginosum", plot_width = 12.5))

  • positive relationship with more conservative communities and TC wetness (sig.)
  • slightly positive relationship with graminoid cover, slightly negative relationship with terrain ruggedness (n.s.)

As the quadratic terms for summer temperature, precipitation and temperature variability were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{

    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.shrub_cov ~ dnorm(0, 0.0001)
      b.gramin_cov ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.tcws ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      b.tempXtcws ~ dnorm(0, 0.001)
      # b.tempXtcws2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.shrub_cov * shrub_cov.dis[i] + 
                        b.gramin_cov * gramin_cov.dis[i] + 
                        b.tempXtcws * tempjja.dis[i] * tcws.dis[i] +       # for interaction
                        # b.tempXtcws2 * (tempjja.dis[i]^2) * tcws.dis[i] +  # for interaction
                        b.tcws * tcws.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.shrub_cov * shrub_cov.cont[j] +
                        b.gramin_cov * gramin_cov.cont[j] +
                        b.tempXtcws * tempjja.cont[j] * tcws.cont[j] +       # for interaction
                        # b.tempXtcws2 * (tempjja.cont[j]^2) * tcws.cont[j] +  # for interaction
                        b.tcws * tcws.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_graminoid_cover[m] <- intercept + b.gramin_cov * xhat_graminoid_cover[m]
        phat_shrub_cover[m] <- intercept + b.shrub_cov * xhat_shrub_cover[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_tcws[m] <- intercept + b.tcws * xhat_tcws[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] # + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] # + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] # + b.precipjja.x2 * (xhat_precipjja[m]^2)
      
        for (p in 1:Nxhat2){
          phat_tempXmoist[m,p] <- intercept +
                                      b.tempjja.x * xhat_tempjja[m] +
                                      # b.tempjja.x2 * (xhat_tempjja[m]^2) +
                                      b.tcws * xhat_tcws2[p] +
                                      b.tempXtcws * xhat_tempjja[m] * xhat_tcws2[p] # +
                                      # b.tempXtcws2 * (xhat_tempjja[m]^2) * xhat_tcws2[p]
          }
        }

    
      }
  ", file.path("..", "models_tcws", "shrub_gradient.VacUli2.jags"))

# specify new set of parameters to be monitored
params_VacUli2 <- c("intercept",
                    "b.tempjja.x", # "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet",
                    "b.shrub_cov",
                    "b.gramin_cov",
                    "b.sri",
                    "b.tri",
                    "b.tcws",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_shrub_cover", "phat_graminoid_cover", 
                    "phat_sri", "phat_tri", "phat_tcws", 
                    "phat_tempjja", "phat_tempcont", "phat_precipjja",
                    "phat_tempXmoist")

model_out.shrub_gradient.VacUli2 <- jags(shrub_gradient_jags.VacUli.data,   # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_VacUli2,                     # parameters to be saved
                                        model.file = file.path("..", "models_tcws", "shrub_gradient.VacUli2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")

# plot(model_out.shrub_gradient.VacUli2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.VacUli2 <- model_out.shrub_gradient.VacUli2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.VacUli2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.VacUli2$BUGSoutput$sims.list)-4)){
  ci_90.VacUli2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.VacUli2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.VacUli2[param, 3] <- names(data.frame(model_out.shrub_gradient.VacUli2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.VacUli2 <- coeff.shrub_gradient.VacUli2 %>% 
  left_join(ci_90.VacUli2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

save(coeff.shrub_gradient.VacUli2, file = file.path("..", "data", "processed", "model_outputs", "species_tcws", "model_output_VacUli2.Rdata"))

# effect size plot
(effect_size_plot.VacUli2 <- model_plot_marg_function(coeff.shrub_gradient.VacUli2, title_string = "Vaccinium uliginosum", plot_width = 9.5))

  • positive relationship with more conservative communities, TCwetness (sig.) and summer temperature (m.s.)
  • slightly positive relationship with graminoid cover and precipitation, negative with terrain heterogeneity (n.s.)


LS0tDQp0aXRsZTogJ1RlbXBlcmF0dXJlIHZhcmlhYmlsaXR5LCBtb2lzdHVyZSBhbmQgYmlvdGljIGludGVyYWN0aW9ucyBkcml2ZSBzaHJ1YiBzcGVjaWVzIGFidW5kYW5jZSBhbG9uZyBhIGNvYXN0YWwtaW5sYW5kIGdyYWRpZW50IGluIGFyY3RpYyBHcmVlbmxhbmQnDQpzdWJ0aXRsZTogPGNlbnRlcj4tIFNlY29uZGFyeSBhbmFseXNpcyB3b3JrZmxvdyB8IFRhc3NlbGVkLWNhcCBXZXRuZXNzIEluZGV4IGFzIHdldG5lc3MgcHJlZGljdG9yIC08L2NlbnRlcj4NCmF1dGhvcjogIkpvbmF0aGFuIHZvbiBPcHBlbiAoam9uYXRoYW4udm9ub3BwZW5AYmlvLmF1LmRrKSBldCBhbC4iDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge3J9DQpybShsaXN0ID0gbHMoKSkNCmBgYA0KDQoNCiMjIERlcGVuZGVuY2llcw0KUGFja2FnZXMgaW5jbHVkZWQ6DQoNCiogdGlkeXZlcnNlIC0gZm9yIGNvbnZlbmllbnQgY29kZSBmbG93LCBkYXRhIHdyYW5nbGluZyBhbmQgcGxvdHRpbmcNCiogcmphZ3MgJiBSMmphZ3MgLSB0byBsaW5rIEpBR1MgYW5kIFINCiogc2tpbXIgLSBmb3IgZGF0YSBzdW1tYXJ5DQoqIGNvcnJyIC0gdG8gb3V0cHV0IGNvcnJlbGF0aW9uIG1hdHJpY2VzIGluIGRhdGFmcmFtZSBmb3JtYXQNCiogY293cGxvdCAmIHBhdGNod29yayAtIHRvIGNvbWJpbmUgcGxvdCBwYW5lbHMNCiogUm1hcmtkb3duIC0gdG8gcHJvZHVjZSB0aGlzIG5lYXQgbGl0dGxlIGRvY3VtZW50YXRpb24NCmBgYHtyIHNldHVwLCBtZXNzYWdlID0gRkFMU0V9DQojIGxvYWQgcGFjbWFuIHBhY2thZ2UgZnJvbSB0aGUgcmVwb3NpdG9yeSwgaWYgeW91IGRvIG5vdCBhbHJlYWR5IGhhdmUgaXQNCmlmICghcmVxdWlyZSgncGFjbWFuJykpIGluc3RhbGwucGFja2FnZXMoJ3BhY21hbicsIHJlcG9zPSJodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmciKQ0KcGFjbWFuOjpwX2xvYWQodGlkeXZlcnNlLCAjIHNldCBvZiBwYWNrYWdlcyBmb3IgZGF0YSBtYW5pcHVsYXRpb24sIGV4cGxvcmF0aW9uIGFuZCB2aXN1YWxpc2F0aW9uDQogICAgICAgICAgICAgICByamFncywgICAgICMgdG8gbGluayBKQUdTIGFuZCBSDQogICAgICAgICAgICAgICBSMmphZ3MsICAgICMgdG8gbGluayBKQUdTIGFuZCBSDQogICAgICAgICAgICAgICBza2ltciwgICAgICMgZm9yIHF1aWNrIGRhdGFmcmFtZSBpbnNwZWN0aW9uDQogICAgICAgICAgICAgICBjb3JyciwgICAgICMgb3V0cHV0IGNvcnJlbGF0aW9uIG1hdHJpY2VzIGFzIGRhdGEgZnJhbWUNCiAgICAgICAgICAgICAgIGNvd3Bsb3QsICAgIyBjb21iaW5lIHBsb3QgcGFuZWxzDQogICAgICAgICAgICAgICBwYXRjaHdvcmssICMgLSItDQogICAgICAgICAgICAgICBybWFya2Rvd24pICMgZm9yIFIgTWFya2Rvd24gZm9ybWF0dGluZw0KYGBgDQoNCkZ1bmN0aW9ucyB1c2VkOiANCg0KKiBlZmZlY3Qgc2l6ZSBwbG90IGZ1bmN0aW9uDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0KIyBmb3IgY2FzZXMgd2l0aCBvbmx5ICdzaWduaWZpY2FudCcgZWZmZWN0cw0KbW9kZWxfcGxvdF9zaWdfZnVuY3Rpb24gPC0gZnVuY3Rpb24obW9kZWxfY29lZmZfb3V0cHV0LCB0aXRsZV9zdHJpbmcsIHBsb3Rfd2lkdGgpIHsNCiAgdGFyZ2V0X3ZhcnMgPC0gYygiYi50ZW1wamphLngiLCAiYi50ZW1wamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgImIudGVtcGNvbnQueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgImIucHJlY2lwamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi5zcmkiLA0KICAgICAgICAgICAgICAgICAgICJiLnRyaSIsDQogICAgICAgICAgICAgICAgICAgImIudGN3cyIsIA0KICAgICAgICAgICAgICAgICAgICJiLnNocnViX2NvdiIsDQogICAgICAgICAgICAgICAgICAgImIuZ3JhbWluX2NvdiIsDQogICAgICAgICAgICAgICAgICAgImIuY29tcGV0IikNCiAgc29sdXRpb25zIDwtIG1vZGVsX2NvZWZmX291dHB1dA0KICBuYW1lcyhzb2x1dGlvbnMpIDwtIGMoInZhcmlhYmxlIiwgInBvc3QubWVhbiIsICJwb3N0LnNkIiwgImw5NSIsICJsOTAiLCAidTkwIiwgInU5NSIsICJSaGF0IikNCiAgc29sdXRpb25zIDwtIHNvbHV0aW9ucyAlPiUgDQogICAgZmlsdGVyKHZhcmlhYmxlICVpbiUgdGFyZ2V0X3ZhcnMpDQogICMgc29sdXRpb25zJHZhcmlhYmxlIDwtIGZhY3Rvcihzb2x1dGlvbnMkdmFyaWFibGUsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiYi50ZW1wamphLngiLCAiYi50ZW1wamphLngyIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLnRlbXBjb250LngiLCAiYi50ZW1wY29udC54MiIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi5wcmVjaXBqamEueCIsICJiLnByZWNpcGpqYS54MiIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi5zcmkiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLnRjd3MiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImIuY29tcGV0IikpDQogIG1pbl92YWx1ZSA8LSBmbG9vcihtaW4oc29sdXRpb25zJGw5NSkpDQogIG1heF92YWx1ZSA8LSBjZWlsaW5nKG1heChzb2x1dGlvbnMkdTk1KSkNCiAgc29sdXRpb25zJHNpZyA8LSAibnMiDQogIHNvbHV0aW9ucyRzaWdbc29sdXRpb25zJGw5NSA8IDAgJiBzb2x1dGlvbnMkdTk1IDwgMF0gPC0gInNpZyINCiAgc29sdXRpb25zJHNpZ1tzb2x1dGlvbnMkbDk1ID4gMCAmIHNvbHV0aW9ucyR1OTUgPiAwXSA8LSAic2lnIg0KICBsYWJlbF9jb2xvdXIgPC0gcmVwKCJibGFjayIsIG5yb3coc29sdXRpb25zKSkNCiAgbGFiZWxfY29sb3VyW3NvbHV0aW9ucyRzaWcgPT0gInNpZyJdIDwtIHRoZW1lX2RhcmtncmVlbg0KICBsYWJlbF9mYWNlIDwtIHJlcCgicGxhaW4iLCBucm93KHNvbHV0aW9ucykpDQogIGxhYmVsX2ZhY2Vbc29sdXRpb25zJHNpZyA9PSAic2lnIl0gPC0gImJvbGQiDQogICMgbGFiZWxfZmFjZVtyZXNwb25zZSA9PSAiVDFfbWVhbiIgJiBzb2x1dGlvbnMkc2lnID09ICJzaWciXSA8LSAiYm9sZCINCiAgdGl0bGVfc3RyaW5nIDwtIHRpdGxlX3N0cmluZw0KICB0aXRsZV9jb2xvdXIgPC0gImdyZXkxMCINCiAgIyBpZihyZXNwb25zZSA9PSAiVDFfbWVhbiIgfCByZXNwb25zZSA9PSAiVDFfYW1wIikgdGl0bGVfY29sb3VyIDwtIHRoZW1lX3JlZA0KICAjIGlmKHJlc3BvbnNlID09ICJUMl9tZWFuIiB8IHJlc3BvbnNlID09ICJUMl9hbXAiKSB0aXRsZV9jb2xvdXIgPC0gdGhlbWVfeWVsbG93DQogICMgaWYocmVzcG9uc2UgPT0gIlQxX21lYW4iKSByZXNwb25zZSA8LSAiU29pbCINCiAgIyBpZihyZXNwb25zZSA9PSAiVDJfbWVhbiIpIHJlc3BvbnNlIDwtICJHcm91bmQiDQogIA0KICANCiAgbW9kZWxfcGxvdF9zaWcgPC0gZ2dwbG90KHNvbHV0aW9ucywgYWVzKHggPSB2YXJpYWJsZSwgeSA9IHBvc3QubWVhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IGw5NSwgeW1heCA9IHU5NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2lnKSkgKw0KICAgIGdlb21fcG9pbnQoKSArDQogICAgZ2VvbV9lcnJvcmJhcih3aWR0aCA9IC44KSArDQogICAgdGhlbWVfY293cGxvdCgxOCkgKw0KICAgIHlsYWIoIkVmZmVjdCBTaXplIChzY2FsZWQpIikgKw0KICAgIHhsYWIoIiIpICsNCiAgICBnZ3RpdGxlKHBhc3RlMCh0aXRsZV9zdHJpbmcpKSArDQogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIHRoZW1lX2RhcmtncmVlbikpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYyhtaW5fdmFsdWUsIG1heF92YWx1ZSksIGJyZWFrcyA9IHNlcShtaW5fdmFsdWUsbWF4X3ZhbHVlLDAuNSkpICsNCiAgICAjIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiYi50ZW1wamphLngiLCAiYi50ZW1wamphLngyIiwNCiAgICAjICAgICAgICAgImIudGVtcGNvbnQueCIsICJiLnRlbXBjb250LngyIiwNCiAgICAjICAgICAgICAgImIucHJlY2lwamphLngiLCAiYi5wcmVjaXBqamEueDIiLA0KICAgICMgICAgICAgICAiYi5zcmkiLA0KICAgICMgICAgICAgICAiYi50cmkiLA0KICAgICMgICAgICAgICAiYi50Y3dzIiwNCiAgICAjICAgICAgICAgImIuY29tcGV0IiksDQogICAgIyAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInN1bW1lciB0ZW1wZXJhdHVyZSIsIGJxdW90ZSguKCJzdW1tZXIiKSAqIiAiKiB0ZW1wZXJhdHVyZV4yKSwNCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkiLCBicXVvdGUoLigidGVtcGVyYXR1cmUiKSAqIiAiKiB2YXJpYWJpbGl0eV4yKSwNCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3VtbWVyIHByZWNpcGl0YXRpb24iLCBicXVvdGUoLigic3VtbWVyIikgKiIgIiogcHJlY2lwaXRhdGlvbl4yKSwNCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic29sYXIgcmFkaWF0aW9uIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRlcnJhaW4gcnVnZ2VkbmVzcyIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb2lzdHVyZSBhdmFpbGFiaWxpdHkiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29tcGV0aXRpb24iKSkgKw0KICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAwLCB4ZW5kID0gcGxvdF93aWR0aCwgeSA9IDAsIHllbmQgPSAwKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBjb2xvdXIgPSBsYWJlbF9jb2xvdXIsIGZhY2UgPSBsYWJlbF9mYWNlKSwNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IHRpdGxlX2NvbG91ciwgZmFjZSA9ICJpdGFsaWMiKSwNCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQogIHJldHVybihtb2RlbF9wbG90X3NpZykNCn0NCg0KIyBmb3IgY2FzZXMgd2l0aCBtYXJnaW5hbCAnc2lnbmlmaWNhbmNlJw0KbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKG1vZGVsX2NvZWZmX291dHB1dCwgdGl0bGVfc3RyaW5nLCBwbG90X3dpZHRoKSB7DQogIHRhcmdldF92YXJzIDwtIGMoImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgImIudGVtcGNvbnQueCIsICJiLnRlbXBjb250LngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi5wcmVjaXBqamEueCIsICJiLnByZWNpcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAiYi50cmkiLA0KICAgICAgICAgICAgICAgICAgICJiLnRjd3MiLCANCiAgICAgICAgICAgICAgICAgICAiYi5zaHJ1Yl9jb3YiLA0KICAgICAgICAgICAgICAgICAgICJiLmdyYW1pbl9jb3YiLA0KICAgICAgICAgICAgICAgICAgICJiLmNvbXBldCIpDQogIHNvbHV0aW9ucyA8LSBtb2RlbF9jb2VmZl9vdXRwdXQNCiAgbmFtZXMoc29sdXRpb25zKSA8LSBjKCJ2YXJpYWJsZSIsICJwb3N0Lm1lYW4iLCAicG9zdC5zZCIsICJsOTUiLCAibDkwIiwgInU5MCIsICJ1OTUiLCAiUmhhdCIpDQogIHNvbHV0aW9ucyA8LSBzb2x1dGlvbnMgJT4lIA0KICAgIGZpbHRlcih2YXJpYWJsZSAlaW4lIHRhcmdldF92YXJzKQ0KICAjIHNvbHV0aW9ucyR2YXJpYWJsZSA8LSBmYWN0b3Ioc29sdXRpb25zJHZhcmlhYmxlLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgImIudGVtcGNvbnQueDIiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImIucHJlY2lwamphLngiLCAiYi5wcmVjaXBqamEueDIiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLnRyaSIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi50Y3dzIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLmNvbXBldCIpKQ0KICBtaW5fdmFsdWUgPC0gZmxvb3IobWluKHNvbHV0aW9ucyRsOTUpKQ0KICBtYXhfdmFsdWUgPC0gY2VpbGluZyhtYXgoc29sdXRpb25zJHU5NSkpDQogIHNvbHV0aW9ucyRzaWcgPC0gIm5zIg0KICBzb2x1dGlvbnMkc2lnW3NvbHV0aW9ucyRsOTUgPCAwICYgc29sdXRpb25zJHU5NSA8IDBdIDwtICJzaWciDQogIHNvbHV0aW9ucyRzaWdbc29sdXRpb25zJGw5NSA+IDAgJiBzb2x1dGlvbnMkdTk1ID4gMF0gPC0gInNpZyINCiAgc29sdXRpb25zJHNpZ1tzb2x1dGlvbnMkbDkwIDwgMCAmIHNvbHV0aW9ucyR1OTAgPCAwICYgc29sdXRpb25zJGw5NSA8IDAgJiBzb2x1dGlvbnMkdTk1ID4gMF0gPC0gIm1hcmciDQogIHNvbHV0aW9ucyRzaWdbc29sdXRpb25zJGw5MCA+IDAgJiBzb2x1dGlvbnMkdTkwID4gMCAmIHNvbHV0aW9ucyRsOTUgPCAwICYgc29sdXRpb25zJHU5NSA+IDBdIDwtICJtYXJnIg0KICBsYWJlbF9jb2xvdXIgPC0gcmVwKCJibGFjayIsIG5yb3coc29sdXRpb25zKSkNCiAgbGFiZWxfY29sb3VyW3NvbHV0aW9ucyRzaWcgPT0gInNpZyJdIDwtIHRoZW1lX2RhcmtncmVlbg0KICBsYWJlbF9jb2xvdXJbc29sdXRpb25zJHNpZyA9PSAibWFyZyJdIDwtIHRoZW1lX3B1cnBsZQ0KICBsYWJlbF9mYWNlIDwtIHJlcCgicGxhaW4iLCBucm93KHNvbHV0aW9ucykpDQogIGxhYmVsX2ZhY2Vbc29sdXRpb25zJHNpZyA9PSAic2lnIl0gPC0gImJvbGQiDQogICMgbGFiZWxfZmFjZVtyZXNwb25zZSA9PSAiVDFfbWVhbiIgJiBzb2x1dGlvbnMkc2lnID09ICJzaWciXSA8LSAiYm9sZCINCiAgdGl0bGVfc3RyaW5nIDwtIHRpdGxlX3N0cmluZw0KICB0aXRsZV9jb2xvdXIgPC0gImdyZXkxMCINCiAgIyBpZihyZXNwb25zZSA9PSAiVDFfbWVhbiIgfCByZXNwb25zZSA9PSAiVDFfYW1wIikgdGl0bGVfY29sb3VyIDwtIHRoZW1lX3JlZA0KICAjIGlmKHJlc3BvbnNlID09ICJUMl9tZWFuIiB8IHJlc3BvbnNlID09ICJUMl9hbXAiKSB0aXRsZV9jb2xvdXIgPC0gdGhlbWVfeWVsbG93DQogICMgaWYocmVzcG9uc2UgPT0gIlQxX21lYW4iKSByZXNwb25zZSA8LSAiU29pbCINCiAgIyBpZihyZXNwb25zZSA9PSAiVDJfbWVhbiIpIHJlc3BvbnNlIDwtICJHcm91bmQiDQogIA0KICANCiAgbW9kZWxfcGxvdF9tYXJnIDwtIGdncGxvdChzb2x1dGlvbnMsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBwb3N0Lm1lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSBsOTUsIHltYXggPSB1OTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNpZykpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fZXJyb3JiYXIod2lkdGggPSAuOCkgKw0KICAgIHRoZW1lX2Nvd3Bsb3QoMTgpICsNCiAgICB5bGFiKCJFZmZlY3QgU2l6ZSAoc2NhbGVkKSIpICsNCiAgICB4bGFiKCIiKSArDQogICAgZ2d0aXRsZShwYXN0ZTAodGl0bGVfc3RyaW5nKSkgKyANCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGModGhlbWVfcHVycGxlLCAiYmxhY2siLCB0aGVtZV9kYXJrZ3JlZW4pKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMobWluX3ZhbHVlLCBtYXhfdmFsdWUpLCBicmVha3MgPSBzZXEobWluX3ZhbHVlLG1heF92YWx1ZSwwLjUpKSArDQogICAgIyBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICAgIyAgICAgICAgICJiLnRlbXBjb250LngiLCAiYi50ZW1wY29udC54MiIsDQogICAgIyAgICAgICAgICJiLnByZWNpcGpqYS54IiwgImIucHJlY2lwamphLngyIiwNCiAgICAjICAgICAgICAgImIuc3JpIiwNCiAgICAjICAgICAgICAgImIudHJpIiwNCiAgICAjICAgICAgICAgImIudGN3cyIsDQogICAgIyAgICAgICAgICJiLmNvbXBldCIpLA0KICAgICMgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJzdW1tZXIgdGVtcGVyYXR1cmUiLCBicXVvdGUoLigic3VtbWVyIikgKiIgIiogdGVtcGVyYXR1cmVeMiksDQogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5IiwgYnF1b3RlKC4oInRlbXBlcmF0dXJlIikgKiIgIiogdmFyaWFiaWxpdHleMiksDQogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN1bW1lciBwcmVjaXBpdGF0aW9uIiwgYnF1b3RlKC4oInN1bW1lciIpICoiICIqIHByZWNpcGl0YXRpb25eMiksDQogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNvbGFyIHJhZGlhdGlvbiIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0ZXJyYWluIHJ1Z2dlZG5lc3MiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9pc3R1cmUgYXZhaWxhYmlsaXR5IiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbXBldGl0aW9uIikpICsNCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMCwgeGVuZCA9IHBsb3Rfd2lkdGgsIHkgPSAwLCB5ZW5kID0gMCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgY29sb3VyID0gbGFiZWxfY29sb3VyLCBmYWNlID0gbGFiZWxfZmFjZSksDQogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSB0aXRsZV9jb2xvdXIsIGZhY2UgPSAiaXRhbGljIiksDQogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KICByZXR1cm4obW9kZWxfcGxvdF9tYXJnKQ0KfQ0KDQpgYGANCg0KQ29sb3VyIHNjaGVtZToNCmBgYHtyfQ0KdGhlbWVfZGFya2dyZWVuIDwtICIjMTM5NDREIg0KdGhlbWVfcHVycGxlIDwtICIjODc1N0IzIg0KYGBgDQoNCiMjIE92ZXJ2aWV3DQoNClRoaXMgcHJvamVjdCBhaW1zIHRvIGRpc2VudGFuZ2xlIGRyaXZlcnMgb2YgYWJ1bmRhbmNlIG9mIGRpZmZlcmVudCBzaHJ1YiBzcGVjaWVzIGFuZCBmdW5jdGlvbmFsIGdyb3VwcyBpbiBhcmN0aWMgdHVuZHJhLg0KDQpBbmFseXNlcyB3aWxsIGludGVncmF0ZSB0d28gbGV2ZWxzIG9mIHZhcmlhdGlvbjogKipwbG90IGdyb3VwICRcdGltZXMkIHRheG9uIGxldmVsKiogZm9yIGNsaW1hdGljIHByZWRpY3RvcnMgKGRlcml2ZWQgZnJvbSBkb3duc2NhbGVkIENIRUxTQSBkYXRhKSwgZHVlIHRvIHRoZWlyIGNvYXJzZXIgKDkwbSkgcmVzb2x1dGlvbiwgYW5kICoqcGxvdCAkXHRpbWVzJCB0YXhvbiBsZXZlbCoqIGZvciBwbG90LWxldmVsICB0b3BvZ3JhcGhpYyBhbmQgYmlvdGljIGludGVyYWN0aW9uIHByZWRpY3RvcnMuIA0KDQpUaGUgdG90YWwgZGF0YXNldCBjb21wcmlzZXMgNDk2OCBvYnNlcnZhdGlvbnMgZm9yIDY2IHZhcmlhYmxlcyAoZGF0YSBjb21waWxhdGlvbiBpcyBkb2N1bWVudGVkIGluIGBzY3JpcHRzL2pvbmF0aGFuL251dWtfc2hydWJfZHJpdmVyc19kYXRhX2NvbXBpbGF0aW9uLlJgKToNCg0KYGBge3J9DQplbnZfY292X2JpbyA8LSByZWFkLmNzdihmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm51dWtfZW52X2NvdmVyX3Bsb3RzLmNzdiIpLCBoZWFkZXIgPSBUKQ0KYGBgDQo8IS0tIDxidXR0b24gY2xhc3M9ImJ0biBidG4tcHJpbWFyeSIgZGF0YS10b2dnbGU9ImNvbGxhcHNlIiBkYXRhLXRhcmdldD0iI0Jsb2NrTmFtZSI+IFNob3cvSGlkZSBEYXRhIFN1bW1hcnkgPC9idXR0b24+IC0tPg0KPCEtLSA8ZGl2IGlkPSJCbG9ja05hbWUiIGNsYXNzPSJjb2xsYXBzZSI+IC0tPg0KPCEtLSBgYGB7cn0gLS0+DQo8IS0tIHNraW0oZW52X2Nvdl9iaW8pIC0tPg0KPCEtLSBgYGAgLS0+DQoNCg0KIyMgRGF0YSBwcmVwYXJhdGlvbiBmb3IgSkFHUyBtb2RlbHMgDQojIyMgYSkgc2VsZWN0aW9uIG9mIHZhcmlhYmxlcyByZWxldmFudCBmb3IgYW5hbHlzaXMNCmluY2x1ZGluZyBwcmVkaWN0b3JzDQoNCiogSW5mb3JtYXRpb24gb24gc2l0ZSwgcGxvdCwgcGxvdCBncm91cCwgc2FtcGxpbmcgbG9jYXRpb24gKGxhdCwgbG9uLCBhbHRpdHVkZSksIHNhbXBsaW5nIHllYXIgDQoqIGRvd25zY2FsZWQgQ0hFTFNBIHByZWRpY3RvcnMsIGF2ZXJhZ2VkIG92ZXIgYSAzMC15ZWFyIHBlcmlvZCAoKlsuLi5dX3RzXzMwKikgDQoqIHNvbGFyIHJhZGlhdGlvbiBpbmRleCAoU1JJLCBmb2xsb3dpbmcgW0tlYXRpbmcgZXQgYWwuIDIwMDddKGh0dHA6Ly93d3cuYmlvb25lLm9yZy9kb2kvYWJzLzEwLjIxOTMvMjAwNi0zNTkpKSwgc2xvcGUgKGVyb3Npb24gbWVhc3VyZSksIFRlcnJhaW4gUnVnZ2VkbmVzcyBJbmRleCAoVFJJLCBmb2xsb3dpbmcgW1JpbGV5IGV0IGFsLiAxOTk5XShodHRwOi8vZG93bmxvYWQub3NnZW8ub3JnL3FnaXMvZG9jL3JlZmVyZW5jZS1kb2NzL1RlcnJhaW5fUnVnZ2VkbmVzc19JbmRleC5wZGYpKSwgVGFzc2VsZWQgQ2FwIFdldG5lc3MgSW5kZXggKFRDV0ksIFtDcmlzdCAmIENpY2NvbmUgMTk4NF0oaHR0cHM6Ly9pZWVleHBsb3JlLmllZWUub3JnL2RvY3VtZW50LzQxNTc1MDcpKSwgVG9wb2dyYXBoaWMgV2V0bmVzcyBJbmRleCAoVFdJLCBzZWUgW0NvbnJhZCBldCBhbC4gMjAxNV0oaHR0cHM6Ly9nbWQuY29wZXJuaWN1cy5vcmcvYXJ0aWNsZXMvOC8xOTkxLzIwMTUvKSkgYmFzZWQgb24gW0ZEOC1RdWlubl0oaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvYWJzLzEwLjEwMDIvaHlwLjMzNjAwNTAxMDYpIGFuZCBbU0FHQS1pbnRlcm5hbF0oaHR0cDovL3d3dy5zYWdhLWdpcy5vcmcvc2FnYV90b29sX2RvYy8yLjIuMi90YV9oeWRyb2xvZ3lfMTUuaHRtbCkgZmxvdyBhbGdvcml0aG1zLCByZXNwZWN0aXZlbHkNCiogY292ZXIgb2Ygb3RoZXIgc2hydWIgc3BlY2llcyAob25seSB1c2VkIGluIHNwZWNpZXMgbW9kZWxzKQ0KKiBjb3ZlciBvZiBncmFtaW5vaWRzDQoqIGNvbXBldGl0aW9uIHByZXNzdXJlIGluIHRoZSBjb21tdW5pdHkgKGFzIHN1bW1lZCBhYnVuZGFuY2Ugb2YgdGFsbGVyLWdyb3dpbmcgc2hydWIgc3BlY2llcyB3aXRoaW4gYSBwbG90LCBhdmVyYWdlZCB3aXRoaW4gcGxvdCBncm91cHMpDQoqIHRheG9uIChzZWUgYmVsb3cgZm9yIGxldmVscykNCg0KYW5kIHJlc3BvbnNlIHZhcmlhYmxlIA0KDQoqIGNvdmVyIChhcyByZWxhdGl2ZSBuby4gaGl0cyBwZXIgcGxvdCBmb3IgZWFjaCBzcGVjaWVzL2dyb3VwKQ0KYGBge3J9DQplbnZfY292X2Jpb19zdWIgPC0gZW52X2Nvdl9iaW8gJT4lIA0KICBzZWxlY3Qoc2l0ZV9hbHRfcGxvdGdyb3VwX2lkLCBwbG90LCBzaXRlLCBzaXRlX2FsdF9pZCwgeWVhciwgbG9uZywgbGF0LCBhbHQsICAjIHBsb3QgaW5mbyAvIG1ldGFkYXRhDQogIGVuZHNfd2l0aCgiX3RzXzMwIiksICAgICAgICAjIENIRUxTQSBwcmVkaWN0b3JzIGF2ZXJhZ2VkIG92ZXIgMzAteWVhciBwZXJpb2QgcHJpb3IgdG8gc3R1ZHkgeWVhcg0KICBpbmNsaW5fZG93biwgc3JpLCB0Y3dzLCB0cmksICMgZW52aXJvbm1lbnRhbCBkYXRhDQogIGVuZHNfd2l0aCgiX2NvdmVyIiksIGNvbXBldCwjIGJpb3RpYyBwcmVkaWN0b3JzOiBzaHJ1YiAmIGNvdmVyLCByZWxhdGl2ZSBjb21wZXRpdGl2ZW5lc3MvYWNxdWlzaXRpdmVuZXNzDQogIHRheG9uLCBjb3ZlcikgICAgICAgICAgICAgICAjIHRheG9uLCBjb3ZlciByZXNwb25zZQ0KaGVhZChlbnZfY292X2Jpb19zdWIpDQpgYGANCg0KTGV0J3MgY2hlY2sgZm9yIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGRpZmZlcmVudCBtb2lzdHVyZSBwcmVkaWN0b3JzIGFuZCB0ZXJyYWluIHJ1Z2dlZG5lc3M6DQoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQooY29yX21vaXN0IDwtIGVudl9jb3ZfYmlvICU+JSANCiAgc2VsZWN0KHR3aV9mZDgsIHR3aV9zYWdhLCB0Y3dzLCB0cmkpKSAlPiUgDQogIGNvcnJlbGF0ZShkaWFnb25hbCA9IDEpDQpgYGANCiRcUmlnaHRhcnJvdyQgVGhlIHR3byBUV0kgYXJlIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlciwgYW5kIGFsc28gcmF0aGVyIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggVFJJLiBBbGwgdGhyZWUgYXJlIGxhcmdlbHkgaW5kZXBlbmRlbnQgZnJvbSBUQ1dTLg0KRm9yIHRoaXMgYWx0ZXJuYXRpdmUgcGF0aHdheSwgd2UnbGwgZ28gd2l0aCBUQ1dTIHRvIGlsbHVzdHJhdGUgZGlmZmVyZW5jZXMgaW4gbW9kZWwgb3V0Y29tZXMgd2l0aCBkaWZmZXJlbnQgd2V0bmVzcyBwcmVkaWN0b3JzLiBDYXV0aW9uOiBhcyBwb2ludGVkIG91dCBieSByZXZpZXdlcnMsIHJlZmxlY3RhbmNlLWJhc2VkIFRDV1MgY2FuIGJlIGNvbmZvdW5kZWQgYnkgdmVnZXRhdGlvbiwgdGhvdWdoIHRoaXMgbWlnaHQgYWxzbyBtYWtlIGl0IG1vcmUgJ2V2aWRlbnRpYWwnIHRoYW4gdGhlIHRlcnJhaW4tYmFzZWQgVFdJLg0KDQo8YnI+DQoNClByZWRpY3RvcnMgZG9uJ3QgYWx3YXlzIHZhcnkgYmV0d2VlbiBwbG90cyB3aXRoaW4gcGxvdGdyb3VwcyAtIHBlcmhhcHMgZHVlIHRvIHNldmVyYWwgZmFsbGluZyBpbnRvIHRoZSBzYW1lIENIRUxTQSBncmlkIGNlbGwuDQoNCkV4YW1wbGU6IHBsb3RzIHdpdGhpbiBzaXRlIDEsIGFsdGl0dWRlIDIwLCBwbG90IGdyb3VwIDE6IHBsb3QgUDE0NiBpcyBzbGlnaHRseSBvZmYgYW5kIHRoZXJlZm9yZSBoYXMgZGlmZmVyZW50IGNsaW1hdGUgdmFyaWFibGVzIHRoYW4gdGhlIG90aGVyIG9uZXMNCg0KVGhlcmVmb3JlIHBsb3Rncm91cC1zY2FsZSAoY2xpbWF0aWMpIHByZWRpY3RvcnMgd2lsbCBoYXZlIHRvIGJlIGF2ZXJhZ2VkIGJlZm9yZSB1c2luZyBpbiBtb2RlbHMhDQoNCmBgYHtyfQ0KZW52X2Nvdl9iaW8gJT4lIGZpbHRlcih0YXhvbiA9PSAiQmV0dWxhIG5hbmEiICYgc2l0ZV9hbHRfcGxvdGdyb3VwX2lkID09ICIxXzIwXzEiKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGxvbmcsIHkgPSBsYXQpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBsb3QpLCBoanVzdCA9IDAuMDAwMSkgKyANCiAgeGxpbShjKC01MS43ODY3NSwgLTUxLjc4NjMpKQ0KZW52X2Nvdl9iaW8gJT4lIGZpbHRlcih0YXhvbiA9PSAiQmV0dWxhIG5hbmEiICYgc2l0ZV9hbHRfcGxvdGdyb3VwX2lkID09ICIxXzIwXzEiKSAlPiUgDQogIHNlbGVjdChzaXRlX2FsdF9wbG90Z3JvdXBfaWQsIHBsb3QsIHRlbXBqamFfdHNfMzApDQpgYGANCg0KQ2hlY2sgZm9yIGNvcnJlbGF0aW9uIGJldHdlZW4gcHJlZGljdG9yczoNCg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCnByZWRpY3RvcnNfc2V0IDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgDQogIHNlbGVjdChlbmRzX3dpdGgoIl90c18zMCIpLCAgICMgQ0hFTFNBIHByZWRpY3RvcnMgYXZlcmFnZWQgb3ZlciAxMC15ZWFyIHBlcmlvZCBwcmlvciB0byBzdHVkeSB5ZWFyDQogICAgICAgICBpbmNsaW5fZG93biwgc3JpLCB0cmksIHRjd3MsICAgICAgIyBlbnZpcm9ubWVudGFsIGRhdGENCiAgICAgICAgIHNocnViX2NvdmVyLCBncmFtaW5vaWRfY292ZXIsIGNvbXBldCkgJT4lICAjIGJpb3RpYyBwcmVkaWN0b3JzDQogIG5hbWVzKCkNCiMgY3JlYXRlIGJhc2ljIGNvcnJlbGF0aW9uIG1hdHJpeA0KKGNvcl9tYXQgPC0gZW52X2Nvdl9iaW9fc3ViICU+JSANCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3JzX3NldCkgJT4lIA0KICBjb3JyZWxhdGUoZGlhZ29uYWwgPSAxKSAlPiUgDQogICMgZHJvcCBhbGwgdmFsdWVzIDwgLjQgdG8gaW5jcmVhc2UgcmVhZGFiaWxpdHkNCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIH4gaWZlbHNlKGFicyguKSA8IC40LCBOQSwgLikpKQ0KYGBgDQoNCiRcUmlnaHRhcnJvdyQgTWF4aW11bSB0ZW1wZXJhdHVyZSBpcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHN1bW1lciB0ZW1wZXJhdHVyZSwgbWluaW11bSB0ZW1wZXJhdHVyZSB3aXRoIGNvbnRpbmVudGFsaXR5LCBzbG9wZSAoaW5jbGluX2Rvd24pIHdpdGggc29sYXIgcmFkaWF0aW9uLCBhbmQgc3ByaW5nIHByZWNpcGl0YXRpb24gdmFyaWFibGVzIHdpdGggc3VtbWVyIHByZWNpcGl0YXRpb24uDQpMZXQncyBleGNsdWRlIHRoZW0gc3RlcCBieSBzdGVwIGFuZCBjaGVjayB0aGUgdmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvcnMgKFZJRikgYWxvbmcgdGhlIHdheS4gVklGIHZhbHVlcyA+IDUgaW5kaWNhdGUgY29sbGluZWFyaXR5IGlzc3Vlcy4NCg0KYGBge3J9DQojIGZvciB0aGUgd2hvbGUgc2V0IG9mIHByZWRpY3RvcnMNCih2aWZfcHJlZGljdG9yc18xIDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgDQogIGRwbHlyOjpzZWxlY3QocHJlZGljdG9yc19zZXQpICU+JSANCiAgdXNkbTo6dmlmKCkpICMlPiUgVmlldygpDQojID0+IGRyb3AgdGVtcG1heCAoY29ycmVsYXRlZCB3LyB0ZW1wamphKQ0KKHZpZl9wcmVkaWN0b3JzXzIgPC0gZW52X2Nvdl9iaW9fc3ViICU+JSANCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3JzX3NldCwNCiAgICAgICAgICAgICAgICAtdGVtcG1heF90c18zMCkgJT4lIA0KICB1c2RtOjp2aWYoKSkgIyU+JSBWaWV3KCkNCiMgPT4gZHJvcCB0ZW1wbWluIChjb3JyZWxhdGVkIHcvIHRlbXBjb250KQ0KKHZpZl9wcmVkaWN0b3JzXzMgPC0gZW52X2Nvdl9iaW9fc3ViICU+JSANCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3JzX3NldCwNCiAgICAgICAgICAgICAgICAtdGVtcG1heF90c18zMCwNCiAgICAgICAgICAgICAgICAtdGVtcG1pbl90c18zMCkgJT4lIA0KICB1c2RtOjp2aWYoKSkgIyU+JSBWaWV3KCkNCiMgPT4gZHJvcCBwcmVjaXBqZm1hbSAoY29ycmVsYXRlZCB3LyBwcmVjaXBqamEgJiB0ZW1wY29udCkNCih2aWZfcHJlZGljdG9yc180IDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgDQogIGRwbHlyOjpzZWxlY3QocHJlZGljdG9yc19zZXQsDQogICAgICAgICAgICAgICAgLXRlbXBtYXhfdHNfMzAsDQogICAgICAgICAgICAgICAgLXRlbXBtaW5fdHNfMzAsDQogICAgICAgICAgICAgICAgLWNvbnRhaW5zKCJqZm0iKSkgJT4lIA0KICB1c2RtOjp2aWYoKSkgIyU+JSBWaWV3KCkNCiMgPT4gZHJvcCBpbmNsaW5fZG93biAoY29ycmVsYXRlZCB3LyBTUkkpDQoodmlmX3ByZWRpY3RvcnNfNSA8LSBlbnZfY292X2Jpb19zdWIgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvcnNfc2V0LA0KICAgICAgICAgICAgICAgIC10ZW1wbWF4X3RzXzMwLA0KICAgICAgICAgICAgICAgIC10ZW1wbWluX3RzXzMwLA0KICAgICAgICAgICAgICAgIC1pbmNsaW5fZG93biwNCiAgICAgICAgICAgICAgICAtY29udGFpbnMoImpmbSIpKSAlPiUgDQogIHVzZG06OnZpZigpKSAjJT4lIFZpZXcoKQ0KIyA9PiBkcm9wIHByZWNpcG1hbSAoY29ycmVsYXRlZCB3LyBwcmVjaXBqamEpDQoodmlmX3ByZWRpY3RvcnNfNiA8LSBlbnZfY292X2Jpb19zdWIgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvcnNfc2V0LA0KICAgICAgICAgICAgICAgIC10ZW1wbWF4X3RzXzMwLA0KICAgICAgICAgICAgICAgIC10ZW1wbWluX3RzXzMwLA0KICAgICAgICAgICAgICAgIC1pbmNsaW5fZG93biwNCiAgICAgICAgICAgICAgICAtY29udGFpbnMoIm1hbSIpKSAlPiUgDQogIHVzZG06OnZpZigpKSAjJT4lIFZpZXcoKQ0KYGBgDQoNCkFsbCBWSUYgYXJlIG5vdyA8IDMgLT4gT0shIFdlIGNhbiBub3cgZXhjbHVkZSB0aGUgZHJvcHBlZCB2YXJpYWJsZXMgdG8gb2J0YWluIHRoZSBmaW5hbCBkYXRhc2V0LiBJbiBhZGRpdGlvbiwgd2UgcmVuYW1lIHRoZSBjbGltYXRlIHZhcmlhYmxlcyBhbmQgZGVsZXRlIHRoZSBleHRlbnNpb246DQoNCmBgYHtyfQ0KZW52X2Nvdl9iaW9fc3ViIDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRlbXBtYXhfdHNfMzAsDQogICAgICAgICAgICAgICAgLXRlbXBtaW5fdHNfMzAsDQogICAgICAgICAgICAgICAgLWluY2xpbl9kb3duLA0KICAgICAgICAgICAgICAgIC1jb250YWlucygibWFtIikpICU+JSANCiAgDQogIHJlbmFtZSh0ZW1wamphID0gdGVtcGpqYV90c18zMCwNCiAgICAgICAgIHRlbXBjb250ID0gdGVtcGNvbnRfdHNfMzAsDQogICAgICAgICBwcmVjaXBqamEgPSBwcmVjaXBqamFfdHNfMzApICU+JSANCiAgDQogIG11dGF0ZSh0YXhvbiA9IGFzLmZhY3Rvcih0YXhvbikpDQpzdHIoZW52X2Nvdl9iaW9fc3ViKQ0KYGBgDQoNCiMjIyBiKSBhZGp1c3Rpb24gb2YgZGF0YSBzdHJ1Y3R1cmUNCg0KRGF0YSBpcyBvcmRlcmVkIGJ5IHNpdGUvYWx0aXR1ZGUvcGxvdGdyb3VwIGFuZCB0YXhvbg0KYGBge3J9DQplbnZfY292X2Jpb19zdWIgPC0gZW52X2Nvdl9iaW9fc3ViW29yZGVyKGVudl9jb3ZfYmlvX3N1YiRzaXRlX2FsdF9wbG90Z3JvdXBfaWQsIGVudl9jb3ZfYmlvX3N1YiR0YXhvbiksXQ0KDQpgYGANCg0KQXMgSkFHUyBpcyBvbmx5IGFibGUgdG8gaGFuZGxlIG51bWVyaWMgaW5wdXQsIGFsbCB2YXJpYWJsZXMgYXJlIGFzc2lnbmVkIGEgbnVtZXJpYyBpZGVudGlmaWVyOg0KYGBge3J9DQplbnZfY292X2Jpb19zdWIkcGxvdGdyb3VwLk5VTSA8LSBhcy5udW1lcmljKGZhY3RvcihlbnZfY292X2Jpb19zdWIkc2l0ZV9hbHRfcGxvdGdyb3VwX2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGVudl9jb3ZfYmlvX3N1YiRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSkNCmVudl9jb3ZfYmlvX3N1YiRwbG90Lk5VTSA8LSBhcy5udW1lcmljKGZhY3RvcihlbnZfY292X2Jpb19zdWIkcGxvdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUoZW52X2Nvdl9iaW9fc3ViJHBsb3QpKSkNCmVudl9jb3ZfYmlvX3N1YiRzaXRlX2FsdC5OVU0gPC0gYXMubnVtZXJpYyhmYWN0b3IoZW52X2Nvdl9iaW9fc3ViJHNpdGVfYWx0X2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZShlbnZfY292X2Jpb19zdWIkc2l0ZV9hbHRfaWQpKSkNCmVudl9jb3ZfYmlvX3N1YiRzaXRlLk5VTSA8LSBhcy5udW1lcmljKGZhY3RvcihlbnZfY292X2Jpb19zdWIkc2l0ZSwgbGV2ZWxzID0gdW5pcXVlKGVudl9jb3ZfYmlvX3N1YiRzaXRlKSkpDQplbnZfY292X2Jpb19zdWIkdGF4b24uTlVNIDwtIGFzLm51bWVyaWMoZmFjdG9yKGVudl9jb3ZfYmlvX3N1YiR0YXhvbiwgbGV2ZWxzID0gdW5pcXVlKGVudl9jb3ZfYmlvX3N1YiR0YXhvbikpKQ0KYGBgDQoNClRheGEgd2VyZSBjb2RlZCBhcyBmb2xsb3dzOiANCmBgYHtyfQ0KZGF0YS5mcmFtZSh0YXhvbiA9IGxldmVscyhlbnZfY292X2Jpb19zdWIkdGF4b24pLA0KICAgICAgICAgICBudW0gPSB1bmlxdWUoZW52X2Nvdl9iaW9fc3ViJHRheG9uLk5VTSkpDQpgYGANCg0KTnVtZXJpYyBwcmVkaWN0b3JzIHdlcmUgc2NhbGVkIGFuZCBjZW50ZXJlZDogDQpgYGB7cn0NCm51bV9wcmVkIDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgc2VsZWN0KHRlbXBqamEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZW1wY29udCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWNpcGpqYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNyaSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0Y3dzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZHNfd2l0aCgiX2NvdmVyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaGVzKCJjb21wZXQiKSkNCmZvcihpIGluIDE6bGVuZ3RoKG51bV9wcmVkKSl7DQogIGNvbCA8LSBjb2xuYW1lcyhudW1fcHJlZFtpXSkNCiAgZW52X2Nvdl9iaW9fc3ViW3Bhc3RlMChjb2wsIkMiKV0gPC0gYXMubnVtZXJpYyhzY2FsZShudW1fcHJlZFtpXSwgc2NhbGUgPSBUUlVFLCBjZW50ZXIgPSBUUlVFKSkNCn0NCmBgYA0KDQpUbyBhY2NvdW50IGZvciB0aGUgcmFuZ2Ugb2YgdGhlIGNvdmVyIHJlc3BvbnNlICgkMCBcbGVxIGNvdmVyIFxsZXEgMSQpLCB0aGUgbW9kZWwgbmVlZHMgYSBtaXhlZCBzdHJ1Y3R1cmUgaW5jb3Jwb3JhdGluZyBhIGJldGEgZGlzdHJpYnV0aW9uIChmb3IgYWxsIGNvbnRpbnVvdXMgdmFsdWVzIHdpdGggJDAgPCBjb3ZlciA8IDEkKSBhbmQgYSBiaW5vbWlhbCBkaXN0cmlidXRpb24gKGZvciBhbGwgZGlzY3JldGUgdmFsdWVzIG9mICRjb3ZlciA9IFx7MCwgMVx9JCkuIEFuIGFkZGl0aW9uYWwgdmFyaWFibGUgKmNvdmVyX2Rpc2NyZXRlKiB3YXMgaW50cm9kdWNlZCB0byBzZXBhcmF0ZSB0aGUgZGF0YXNldCBpbnRvIGRpc2NyZXRlICg9IDEpIGFuZCBjb250aW51b3VzICg9IDApIGNvdmVyIHZhbHVlczoNCmBgYHtyfQ0KZW52X2Nvdl9iaW9fc3ViJGNvdmVyX2Rpc2NyZXRlIDwtIGlmZWxzZShlbnZfY292X2Jpb19zdWIkY292ZXIgPT0gMSB8IGVudl9jb3ZfYmlvX3N1YiRjb3ZlciA9PSAwLCAxLCAwKQ0KYGBgDQoNCg0KPGJyPg0KDQojIyBKQUdTIG1vZGVscw0KVGhlIGRhdGFzZXQgd2FzIHRoZW4gcmVhZHkgdG8gYmUgc3BsaXQgdXAgaW50byB0aGUgc3BlY2llcyBvZiBpbnRlcmVzdC4gV2UgY3JlYXRlIHNlcGFyYXRlIGRhdGEgc3Vic2V0cyBmb3IgYWxsL2Rpc2NyZXRlL2NvbnRpbnVvdXMgcmVzcG9uc2UgdmFyaWFibGUgdmFsdWVzIGZvciBlYWNoIHNwZWNpZXM6DQpgYGB7cn0NCiMgc3BsaXQgZGF0YWZyYW1lIGJ5IHRheG9uDQplbnZfY292X2Jpb19zdWJfc3BlYy50b3QgPC0gc3BsaXQoZW52X2Nvdl9iaW9fc3ViLCBlbnZfY292X2Jpb19zdWIkdGF4b24pDQoNCiMgYXNzaWduIHRheG9uIG5hbWUgdG8gbGlzdCBlbGVtZW50cw0KIyA+PiBmb3IgdG90YWwgZGF0YXNldHMNCmZvciAodGF4b25faWQgaW4gMTpubGV2ZWxzKGVudl9jb3ZfYmlvX3N1YiR0YXhvbikpew0KICAjIGV4dHJhY3QgMy1sZXR0ZXIgZ2VudXMgbmFtZSBzdHJpbmcNCiAgYXNzaWduKHBhc3RlMChzdHJfZXh0cmFjdChsZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKVt0YXhvbl9pZF0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJeXFx3ezN9IiksDQogICMgZXh0cmFjdCBhbmQgY2FwaXRhbGlzZSAzLWxldHRlciBzcGVjaWVzIG5hbWUgc3RyaW5nDQogICAgICAgICAgICAgICAgc3RyX3RvX3RpdGxlKHN0cl9yZW1vdmUoc3RyX2V4dHJhY3QobGV2ZWxzKGVudl9jb3ZfYmlvX3N1YiR0YXhvbilbdGF4b25faWRdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcXHNcXHd7M30iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXFxzIikpLA0KICAjIGFkZCBleHRlbnNpb24NCiAgICAgICAgICAgICAgICAiLnRvdCIpLA0KICAjIGFzc2lnbiB0byByZXNwZWN0aXZlIGxpc3QgZWxlbWVudA0KICAgICAgICAgZW52X2Nvdl9iaW9fc3ViX3NwZWMudG90W1t0YXhvbl9pZF1dKQ0KfQ0KDQoNCg0KIyA+PiBmb3IgZGlzY3JldGUgZGF0YXNldHMNCmVudl9jb3ZfYmlvX3N1Yl9zcGVjLmRpcyA8LSBsaXN0KCkNCmZvciAodGF4b25faWQgaW4gMTpubGV2ZWxzKGVudl9jb3ZfYmlvX3N1YiR0YXhvbikpew0KICAjIGZpbHRlciBmb3IgZGlzY3JldGUgcmVzcG9uc2UgdmFsdWVzDQogIGVudl9jb3ZfYmlvX3N1Yl9zcGVjLmRpc1tbdGF4b25faWRdXSA8LSBmaWx0ZXIoZW52X2Nvdl9iaW9fc3ViX3NwZWMudG90W1t0YXhvbl9pZF1dLCBjb3Zlcl9kaXNjcmV0ZSA9PSAxKQ0KICAjIGV4dHJhY3QgMy1sZXR0ZXIgZ2VudXMgbmFtZSBzdHJpbmcNCiAgYXNzaWduKHBhc3RlMChzdHJfZXh0cmFjdChsZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKVt0YXhvbl9pZF0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJeXFx3ezN9IiksDQogICMgZXh0cmFjdCBhbmQgY2FwaXRhbGlzZSAzLWxldHRlciBzcGVjaWVzIG5hbWUgc3RyaW5nDQogICAgICAgICAgICAgICAgc3RyX3RvX3RpdGxlKHN0cl9yZW1vdmUoc3RyX2V4dHJhY3QobGV2ZWxzKGVudl9jb3ZfYmlvX3N1YiR0YXhvbilbdGF4b25faWRdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcXHNcXHd7M30iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXFxzIikpLA0KICAjIGFkZCBleHRlbnNpb24NCiAgICAgICAgICAgICAgICAiLmRpcyIpLA0KICAjIGFzc2lnbiB0byByZXNwZWN0aXZlIGxpc3QgZWxlbWVudA0KICAgICAgICAgZW52X2Nvdl9iaW9fc3ViX3NwZWMuZGlzW1t0YXhvbl9pZF1dKQ0KfQ0KDQojID4+IGZvciBjb250aW51b3VzIGRhdGFzZXRzDQplbnZfY292X2Jpb19zdWJfc3BlYy5jb250IDwtIGxpc3QoKQ0KZm9yICh0YXhvbl9pZCBpbiAxOm5sZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKSl7DQogICMgZmlsdGVyIGZvciBjb250aW51b3VzIHJlc3BvbnNlIHZhbHVlcw0KICBlbnZfY292X2Jpb19zdWJfc3BlYy5jb250W1t0YXhvbl9pZF1dIDwtIGZpbHRlcihlbnZfY292X2Jpb19zdWJfc3BlYy50b3RbW3RheG9uX2lkXV0sIGNvdmVyX2Rpc2NyZXRlID09IDApDQogICMgZXh0cmFjdCAzLWxldHRlciBnZW51cyBuYW1lIHN0cmluZw0KICBhc3NpZ24ocGFzdGUwKHN0cl9leHRyYWN0KGxldmVscyhlbnZfY292X2Jpb19zdWIkdGF4b24pW3RheG9uX2lkXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIl5cXHd7M30iKSwNCiAgIyBleHRyYWN0IGFuZCBjYXBpdGFsaXNlIDMtbGV0dGVyIHNwZWNpZXMgbmFtZSBzdHJpbmcNCiAgICAgICAgICAgICAgICBzdHJfdG9fdGl0bGUoc3RyX3JlbW92ZShzdHJfZXh0cmFjdChsZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKVt0YXhvbl9pZF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxcc1xcd3szfSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcXHMiKSksDQogICMgYWRkIGV4dGVuc2lvbg0KICAgICAgICAgICAgICAgICIuY29udCIpLA0KICAjIGFzc2lnbiB0byByZXNwZWN0aXZlIGxpc3QgZWxlbWVudA0KICAgICAgICAgZW52X2Nvdl9iaW9fc3ViX3NwZWMuY29udFtbdGF4b25faWRdXSkNCn0NCg0KIyBzYXZlIGFsbCBpbnB1dCBkYXRhDQojIGdyb3Vwcw0Kc2F2ZShsaXN0ID0gYygiQWxsU2hyLnRvdCIsDQogICAgICAgICAgICAgICJBbGxFdmUudG90IiwNCiAgICAgICAgICAgICAgIkFsbERlYy50b3QiKSwNCiAgICAgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfaW5wdXRfZGF0YV90Y3dzIiwgInNocnViX2dyYWRpZW50X2dyb3VwLmRhdGFzZXRzLlJkYXRhIikpDQoNCiMgc3BlY2llcw0KIyBncm91cHMNCnNhdmUobGlzdCA9IGMoIkJldE5hbi50b3QiLA0KICAgICAgICAgICAgICAiQ2FzVGV0LnRvdCIsDQogICAgICAgICAgICAgICJFbXBOaWcudG90IiwNCiAgICAgICAgICAgICAgIlBoeUNhZS50b3QiLA0KICAgICAgICAgICAgICAiUmhvR3JvLnRvdCIsDQogICAgICAgICAgICAgICJSaG9Ub20udG90IiwNCiAgICAgICAgICAgICAgIlNhbEFyYy50b3QiLA0KICAgICAgICAgICAgICAiU2FsR2xhLnRvdCIsDQogICAgICAgICAgICAgICJWYWNVbGkudG90IiksDQogICAgIGZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX2lucHV0X2RhdGFfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudF9zcGVjaWVzLmRhdGFzZXRzLlJkYXRhIikpDQoNCmBgYA0KDQojIyMgR3JvdXBzDQojIyMgPiBhc3NlbWJsaW5nIGRhdGEgZm9yIG1vZGVsIGlucHV0IGluIGxpc3RzDQoNCkpBR1MgbmVlZHMgZGF0YSBpbnB1dCBpbiBsaXN0IGZvcm1hdCwgc28gYWxsIHJlbGV2YW50IHZhcmlhYmxlcyBhcmUgY29tcGlsZWQgaW50byBsaXN0czoNCmBgYHtyfQ0KIyBDb21waWxlIGRhdGEgaW50byBsaXN0cw0KIyBBbGwgc2hydWJzIC0tLS0NCnNocnViX2dyYWRpZW50X2phZ3MuQWxsU2hyLmRhdGEgPC0gbGlzdCgNCiAgDQogICMgcGxvdCBsZXZlbCBwcmVkaWN0b3JzDQogIGNvdi50b3QgPSBBbGxTaHIudG90JGNvdmVyICsgMSwNCiAgcGxvdGdyb3VwLnRvdCA9IEFsbFNoci50b3QkcGxvdGdyb3VwLk5VTSwNCiAgc3JpLnRvdCA9IEFsbFNoci50b3Qkc3JpQywNCiAgdHJpLnRvdCA9IEFsbFNoci50b3QkdHJpQywNCiAgdGN3cy50b3QgPSBBbGxTaHIudG90JHRjd3NDLA0KICBncmFtaW5fY292LnRvdCA9IEFsbFNoci50b3QkZ3JhbWlub2lkX2NvdmVyQywNCiAgdGVtcGpqYS50b3QucGxvdCA9IEFsbFNoci50b3QkdGVtcGpqYUMsDQogIE5fcGxvdHMgPSBsZW5ndGgodW5pcXVlKEFsbFNoci50b3QkcGxvdCkpLA0KICANCiAgIyBwbG90IGdyb3VwIGxldmVsIHByZWRpY3RvcnMNCiAgdGVtcGpqYS50b3QgPSBBbGxTaHIudG90ICU+JSBncm91cF9ieShwbG90Z3JvdXAuTlVNKSAlPiUgc3VtbWFyaXNlKHRlbXBqamEudG90ID0gbWVhbih0ZW1wamphQykpICU+JSBwdWxsKHRlbXBqamEudG90KSwgIyBvbmUgdmFsdWUgcGVyIHRYcGcNCiAgdGVtcGNvbnQudG90ID0gQWxsU2hyLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wY29udC50b3QgPSBtZWFuKHRlbXBjb250QykpICU+JSBwdWxsKHRlbXBjb250LnRvdCksDQogIHByZWNpcGpqYS50b3QgPSBBbGxTaHIudG90ICU+JSBncm91cF9ieShwbG90Z3JvdXAuTlVNKSAlPiUgc3VtbWFyaXNlKHByZWNpcGpqYS50b3QgPSBtZWFuKHByZWNpcGpqYUMpKSAlPiUgcHVsbChwcmVjaXBqamEudG90KSwNCiAgTl9wbG90Z3JvdXBzID0gbGVuZ3RoKHVuaXF1ZShBbGxTaHIudG90JHNpdGVfYWx0X3Bsb3Rncm91cF9pZCkpLA0KICANCiAgIyBzdWJzZXQgb2YgdmFsdWVzIGZvciBwcmVkaWN0aW9uLCBmb3IgZWFjaCBwcmVkaWN0b3IuLi4NCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihBbGxTaHIudG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChBbGxTaHIudG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihBbGxTaHIudG90JHNyaUMpLCB0byA9IG1heChBbGxTaHIudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihBbGxTaHIudG90JHRyaUMpLCB0byA9IG1heChBbGxTaHIudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oQWxsU2hyLnRvdCR0Y3dzQyksIHRvID0gbWF4KEFsbFNoci50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oQWxsU2hyLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KEFsbFNoci50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihBbGxTaHIudG90JHByZWNpcGpqYUMpLCB0byA9IG1heChBbGxTaHIudG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKEFsbFNoci50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoQWxsU2hyLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoQWxsU2hyLnRvdCR0Y3dzQywwLjA1KSxxdWFudGlsZShBbGxTaHIudG90JHRjd3NDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5BbGxTaHIuZGF0YSkNCg0KIyBBbGwgZXZlcmdyZWVuIHNocnVicyAtLS0tDQpzaHJ1Yl9ncmFkaWVudF9qYWdzLkFsbEV2ZS5kYXRhIDwtIGxpc3QoDQogIA0KICAjIHBsb3QgbGV2ZWwgcHJlZGljdG9ycw0KICBjb3YudG90ID0gQWxsRXZlLnRvdCRjb3ZlciArIDEsDQogIHBsb3Rncm91cC50b3QgPSBBbGxFdmUudG90JHBsb3Rncm91cC5OVU0sDQogIHNyaS50b3QgPSBBbGxFdmUudG90JHNyaUMsDQogIHRyaS50b3QgPSBBbGxFdmUudG90JHRyaUMsDQogIHRjd3MudG90ID0gQWxsRXZlLnRvdCR0Y3dzQywNCiAgZ3JhbWluX2Nvdi50b3QgPSBBbGxFdmUudG90JGdyYW1pbm9pZF9jb3ZlckMsDQogIHRlbXBqamEudG90LnBsb3QgPSBBbGxFdmUudG90JHRlbXBqamFDLA0KICBOX3Bsb3RzID0gbGVuZ3RoKHVuaXF1ZShBbGxFdmUudG90JHBsb3QpKSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gQWxsRXZlLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IEFsbEV2ZS50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gQWxsRXZlLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoQWxsRXZlLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfZ3JhbWlub2lkX2NvdmVyID0gc2VxKGZyb20gPSBtaW4oQWxsRXZlLnRvdCRncmFtaW5vaWRfY292ZXJDKSwgdG8gPSBtYXgoQWxsRXZlLnRvdCRncmFtaW5vaWRfY292ZXJDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc3JpID0gc2VxKGZyb20gPSBtaW4oQWxsRXZlLnRvdCRzcmlDKSwgdG8gPSBtYXgoQWxsRXZlLnRvdCRzcmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdHJpID0gc2VxKGZyb20gPSBtaW4oQWxsRXZlLnRvdCR0cmlDKSwgdG8gPSBtYXgoQWxsRXZlLnRvdCR0cmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGN3cyA9IHNlcShmcm9tID0gbWluKEFsbEV2ZS50b3QkdGN3c0MpLCB0byA9IG1heChBbGxFdmUudG90JHRjd3NDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGpqYSA9IHNlcShmcm9tID0gbWluKEFsbEV2ZS50b3QkdGVtcGpqYUMpLCB0byA9IG1heChBbGxFdmUudG90JHRlbXBqamFDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfcHJlY2lwamphID0gc2VxKGZyb20gPSBtaW4oQWxsRXZlLnRvdCRwcmVjaXBqamFDKSwgdG8gPSBtYXgoQWxsRXZlLnRvdCRwcmVjaXBqamFDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGNvbnQgPSBzZXEoZnJvbSA9IG1pbihBbGxFdmUudG90JHRlbXBjb250QyksIHRvID0gbWF4KEFsbEV2ZS50b3QkdGVtcGNvbnRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIE54aGF0ID0gMTAwLA0KICANCiAgIyAuLi4gYW5kIGZvciBwcmVkaWN0aW5nIGF0IGhpZ2gvbG93IHRlbXBlcmF0dXJlIGxldmVscw0KICB4aGF0X3Rjd3MyID0gYXMubnVtZXJpYyhjKHF1YW50aWxlKEFsbEV2ZS50b3QkdGN3c0MsMC4wNSkscXVhbnRpbGUoQWxsRXZlLnRvdCR0Y3dzQywwLjk1KSkpLCANCiAgTnhoYXQyID0gMg0KKQ0Kc3RyKHNocnViX2dyYWRpZW50X2phZ3MuQWxsRXZlLmRhdGEpDQoNCiMgQWxsIGRlY2lkaW91cyBzaHJ1YnMgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5BbGxEZWMuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMNCiAgY292LnRvdCA9IEFsbERlYy50b3QkY292ZXIgKyAxLA0KICBwbG90Z3JvdXAudG90ID0gQWxsRGVjLnRvdCRwbG90Z3JvdXAuTlVNLA0KICBzcmkudG90ID0gQWxsRGVjLnRvdCRzcmlDLA0KICB0cmkudG90ID0gQWxsRGVjLnRvdCR0cmlDLA0KICB0Y3dzLnRvdCA9IEFsbERlYy50b3QkdGN3c0MsDQogIGdyYW1pbl9jb3YudG90ID0gQWxsRGVjLnRvdCRncmFtaW5vaWRfY292ZXJDLA0KICB0ZW1wamphLnRvdC5wbG90ID0gQWxsRGVjLnRvdCR0ZW1wamphQywNCiAgTl9wbG90cyA9IGxlbmd0aCh1bmlxdWUoQWxsRGVjLnRvdCRwbG90KSksDQogIA0KICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycw0KICB0ZW1wamphLnRvdCA9IEFsbERlYy50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGpqYS50b3QgPSBtZWFuKHRlbXBqamFDKSkgJT4lIHB1bGwodGVtcGpqYS50b3QpLCAjIG9uZSB2YWx1ZSBwZXIgdFhwZw0KICB0ZW1wY29udC50b3QgPSBBbGxEZWMudG90ICU+JSBncm91cF9ieShwbG90Z3JvdXAuTlVNKSAlPiUgc3VtbWFyaXNlKHRlbXBjb250LnRvdCA9IG1lYW4odGVtcGNvbnRDKSkgJT4lIHB1bGwodGVtcGNvbnQudG90KSwNCiAgcHJlY2lwamphLnRvdCA9IEFsbERlYy50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UocHJlY2lwamphLnRvdCA9IG1lYW4ocHJlY2lwamphQykpICU+JSBwdWxsKHByZWNpcGpqYS50b3QpLA0KICBOX3Bsb3Rncm91cHMgPSBsZW5ndGgodW5pcXVlKEFsbERlYy50b3Qkc2l0ZV9hbHRfcGxvdGdyb3VwX2lkKSksDQogIA0KICAjIHN1YnNldCBvZiB2YWx1ZXMgZm9yIHByZWRpY3Rpb24sIGZvciBlYWNoIHByZWRpY3Rvci4uLg0KICB4aGF0X2dyYW1pbm9pZF9jb3ZlciA9IHNlcShmcm9tID0gbWluKEFsbERlYy50b3QkZ3JhbWlub2lkX2NvdmVyQyksIHRvID0gbWF4KEFsbERlYy50b3QkZ3JhbWlub2lkX2NvdmVyQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3NyaSA9IHNlcShmcm9tID0gbWluKEFsbERlYy50b3Qkc3JpQyksIHRvID0gbWF4KEFsbERlYy50b3Qkc3JpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RyaSA9IHNlcShmcm9tID0gbWluKEFsbERlYy50b3QkdHJpQyksIHRvID0gbWF4KEFsbERlYy50b3QkdHJpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3Rjd3MgPSBzZXEoZnJvbSA9IG1pbihBbGxEZWMudG90JHRjd3NDKSwgdG8gPSBtYXgoQWxsRGVjLnRvdCR0Y3dzQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBqamEgPSBzZXEoZnJvbSA9IG1pbihBbGxEZWMudG90JHRlbXBqamFDKSwgdG8gPSBtYXgoQWxsRGVjLnRvdCR0ZW1wamphQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3ByZWNpcGpqYSA9IHNlcShmcm9tID0gbWluKEFsbERlYy50b3QkcHJlY2lwamphQyksIHRvID0gbWF4KEFsbERlYy50b3QkcHJlY2lwamphQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBjb250ID0gc2VxKGZyb20gPSBtaW4oQWxsRGVjLnRvdCR0ZW1wY29udEMpLCB0byA9IG1heChBbGxEZWMudG90JHRlbXBjb250QyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICBOeGhhdCA9IDEwMCwNCiAgDQogICMgLi4uIGFuZCBmb3IgcHJlZGljdGluZyBhdCBoaWdoL2xvdyB0ZW1wZXJhdHVyZSBsZXZlbHMNCiAgeGhhdF90Y3dzMiA9IGFzLm51bWVyaWMoYyhxdWFudGlsZShBbGxEZWMudG90JHRjd3NDLDAuMDUpLHF1YW50aWxlKEFsbERlYy50b3QkdGN3c0MsMC45NSkpKSwgDQogIE54aGF0MiA9IDINCikNCnN0cihzaHJ1Yl9ncmFkaWVudF9qYWdzLkFsbERlYy5kYXRhKQ0KDQoNCiMgIyBzYXZlIG1vZGVsIGlucHV0IGRhdGENCiMgc2hydWJfZ3JhZGllbnRfamFncy5ncm91cGRhdGEgPC0gbGlzdA0KDQpzYXZlKGxpc3QgPSBjKCJzaHJ1Yl9ncmFkaWVudF9qYWdzLkFsbFNoci5kYXRhIiwNCiAgICAgICAgICAgICAgInNocnViX2dyYWRpZW50X2phZ3MuQWxsRXZlLmRhdGEiLA0KICAgICAgICAgICAgICAic2hydWJfZ3JhZGllbnRfamFncy5BbGxEZWMuZGF0YSIpLA0KICAgICBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9pbnB1dF9kYXRhX3Rjd3MiLCAic2hydWJfZ3JhZGllbnRfamFncy5ncm91cGRhdGEuUmRhdGEiKSkNCmBgYA0KDQojIyMgPiBzcGVjaWZ5aW5nIG1vZGVsDQpgYGB7cn0NCndyaXRlKCINCiAgDQogIG1vZGVsew0KICAgIA0KICAgICMgcHJpb3JzDQogICAgICANCiAgICAgIGludGVyY2VwdCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIA0KICAgICAgYi5ncmFtaW5fY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zcmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudGN3cyB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdCB+IGR1bmlmKDAsMTAwKQ0KICAgICAgdGF1LnBsb3QgPC0gMS8oc2lnbWEucGxvdCAqIHNpZ21hLnBsb3QpDQogICAgICANCiAgICAgIHNpZ21hLnBsb3Rncm91cCB+IGR1bmlmKDAsMTAwKQ0KICAgICAgdGF1LnBsb3Rncm91cCA8LSAxLyhzaWdtYS5wbG90Z3JvdXAgKiBzaWdtYS5wbG90Z3JvdXApDQogICAgICANCiAgICAgIGIudGVtcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi5wcmVjaXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgYi50ZW1wWHRjd3MgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcFh0Y3dzMiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICANCiAgICAjIHBsb3QgbGV2ZWwNCg0KICAgICAgZm9yIChpIGluIDE6Tl9wbG90cyl7IA0KICAgICAgICBjb3YudG90W2ldIH4gZGxub3JtKG11LnBsb3RbaV0sIHRhdS5wbG90KQ0KICAgICAgICBsb2cobXUucGxvdFtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLnRvdFtpXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5ncmFtaW5fY292ICogZ3JhbWluX2Nvdi50b3RbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MudG90W2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEudG90LnBsb3RbaV0gKiB0Y3dzLnRvdFtpXSArICAgICAgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3czIgKiAodGVtcGpqYS50b3QucGxvdFtpXV4yKSAqIHRjd3MudG90W2ldICsgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS50b3RbaV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkudG90W2ldDQogICAgICB9DQoNCg0KICAgICMgcGxvdCBncm91cCBsZXZlbA0KICAgIA0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54MiAqICh0ZW1wY29udC50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54ICogcHJlY2lwamphLnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpIA0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAgICMgYWRkIHByZWRpY3RlZCB2YWx1ZXMgKGRlcml2ZWQgcGFyYW1ldGVycykNCiAgICAgIGZvciAobSBpbiAxOk54aGF0KXsNCiAgICAgICAgcGhhdF9ncmFtaW5vaWRfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5ncmFtaW5fY292ICogeGhhdF9ncmFtaW5vaWRfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zcmlbbV0gPC0gaW50ZXJjZXB0ICsgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnRyaSAqIHhoYXRfdHJpW21dDQogICAgICAgIHBoYXRfdGN3c1ttXSA8LSBpbnRlcmNlcHQgKyBiLnRjd3MgKiB4aGF0X3Rjd3NbbV0NCiAgICAgICAgcGhhdF90ZW1wamphW21dIDwtIGludGVyY2VwdCArIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICsgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKQ0KICAgICAgICBwaGF0X3RlbXBjb250W21dIDwtIGludGVyY2VwdCArIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gKyBiLnRlbXBjb250LngyICogKHhoYXRfdGVtcGNvbnRbbV1eMikNCiAgICAgICAgcGhhdF9wcmVjaXBqamFbbV0gPC0gaW50ZXJjZXB0ICsgYi5wcmVjaXBqamEueCAqIHhoYXRfcHJlY2lwamphW21dICsgYi5wcmVjaXBqamEueDIgKiAoeGhhdF9wcmVjaXBqamFbbV1eMikNCiAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcFhtb2lzdFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHhoYXRfdGVtcGpqYVttXSAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3czIgKiAoeGhhdF90ZW1wamphW21dXjIpICogeGhhdF90Y3dzMltwXQ0KICAgICAgICB9DQogICAgICB9DQoNCiAgICANCiAgICAgIH0NCiAgIiwgZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5ncm91cHMuamFncyIpKQ0KYGBgDQoNClNwZWNpZnkgdGhlIHBhcmFtZXRlcnMgdG8gYmUgbW9uaXRvcmVkOg0KYGBge3J9DQpwYXJhbXNfZ3JvdXBzIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgImIudGVtcGNvbnQueCIsICJiLnRlbXBjb250LngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi5wcmVjaXBqamEueCIsICJiLnByZWNpcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgImIuZ3JhbWluX2NvdiIsDQogICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAiYi50cmkiLA0KICAgICAgICAgICAgICAgICAgICJiLnRjd3MiLA0KICAgICAgICAgICAgICAgICAgICJiX3Bsb3Rncm91cFsxXSIsImJfcGxvdGdyb3VwWzJdIiwiYl9wbG90Z3JvdXBbM10iLCJiX3Bsb3Rncm91cFs2M10iLA0KICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICJwaGF0X2dyYW1pbm9pZF9jb3ZlciIsIA0KICAgICAgICAgICAgICAgICAgICJwaGF0X3NyaSIsICJwaGF0X3Rjd3MiLCAicGhhdF90cmkiLCANCiAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wamphIiwgInBoYXRfdGVtcGNvbnQiLCAicGhhdF9wcmVjaXBqamEiLA0KICAgICAgICAgICAgICAgICAgICJwaGF0X3RlbXBYbW9pc3QiKQ0KYGBgDQoNCiMjIyA+IHJ1biAmIGV2YWx1YXRlIG1vZGVsDQo8YnI+DQoNCiMjIyAqQWxsIHNocnVicyoNCmBgYHtyfQ0KIyBydW4gbW9kZWwNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxTaHIgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLkFsbFNoci5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX2dyb3VwcywgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuZ3JvdXBzLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpIA0KDQojIHBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbFNocikgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxTaHIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbFNociRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsU2hyKSwiW1tdIixmaXhlZD1GQUxTRSksICJbIiwgMSkpKSAjJT4lIHByaW50DQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLkFsbFNociA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbFNociRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5BbGxTaHJbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxTaHIkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuQWxsU2hyW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxTaHIkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsU2hyIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LkFsbFNociAlPiUgDQogIGxlZnRfam9pbihjaV85MC5BbGxTaHIsIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCnNhdmUoY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsU2hyLCANCiAgICAgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJncm91cHNfdGN3cyIsICJmaXJzdF9ydW5zX2NvbnZlcmdlZCIsICJtb2RlbF9vdXRwdXRfQWxsU2hyLlJkYXRhIikpDQoNCihlZmZlY3Rfc2l6ZV9wbG90LkFsbFNociA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxTaHIsIHRpdGxlX3N0cmluZyA9ICJhbGwgc2hydWJzIiwgcGxvdF93aWR0aCA9IDEwLjUpKQ0KYGBgDQoNCiogKipwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBUQyB3ZXRuZXNzLCBuZWdhdGl2ZSByZXNwb25zZSB0byBncmFtaW5vaWQgY292ZXIgKHNpZy4pKioNCiogc2xpZ2h0bHkgcG9zaXRpdmUgcmVzcG9uc2UgdG8gc29sYXIgcmFkaWF0aW9uIChuLnMuKQ0KDQo8YnI+DQoNCkFzIG5vbmUgb2YgdGhlIHF1YWRyYXRpYyB0ZXJtcyBmb3IgY2xpbWF0aWMgdmFyaWFibGVzIGNhbWUgb3V0IHNpZ25pZmljYW50LCByZS1ydW4gd2l0aG91dCB0aGVtOg0KYGBge3J9DQp3cml0ZSgiDQogIA0KICBtb2RlbHsNCiAgICANCiAgICAjIHByaW9ycw0KICAgICAgDQogICAgICBpbnRlcmNlcHQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICANCiAgICAgIGIuZ3JhbWluX2NvdiB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc3JpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50cmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRjd3MgfiBkbm9ybSgwLCAwLjAwMDEpDQoNCiAgICAgIHNpZ21hLnBsb3QgfiBkdW5pZigwLDEwMCkNCiAgICAgIHRhdS5wbG90IDwtIDEvKHNpZ21hLnBsb3QgKiBzaWdtYS5wbG90KQ0KICAgICAgDQogICAgICBzaWdtYS5wbG90Z3JvdXAgfiBkdW5pZigwLDEwMCkNCiAgICAgIHRhdS5wbG90Z3JvdXAgPC0gMS8oc2lnbWEucGxvdGdyb3VwICogc2lnbWEucGxvdGdyb3VwKQ0KICAgICAgDQogICAgICBiLnRlbXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBjb250LngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnByZWNpcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIucHJlY2lwamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIGIudGVtcFh0Y3dzIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcFh0Y3dzMiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICANCiAgICAjIHBsb3QgbGV2ZWwNCg0KICAgICAgZm9yIChpIGluIDE6Tl9wbG90cyl7IA0KICAgICAgICBjb3YudG90W2ldIH4gZGxub3JtKG11LnBsb3RbaV0sIHRhdS5wbG90KQ0KICAgICAgICBsb2cobXUucGxvdFtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLnRvdFtpXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5ncmFtaW5fY292ICogZ3JhbWluX2Nvdi50b3RbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MudG90W2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEudG90LnBsb3RbaV0gKiB0Y3dzLnRvdFtpXSArICAgICAgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcFh0Y3dzMiAqICh0ZW1wamphLnRvdC5wbG90W2ldXjIpICogdGN3cy50b3RbaV0gKyAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLnRvdFtpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS50b3RbaV0NCiAgICAgIH0NCg0KDQogICAgIyBwbG90IGdyb3VwIGxldmVsDQogICAgDQogICAgICBmb3IgKGsgaW4gMTpOX3Bsb3Rncm91cHMpeyAjIGxlbmd0aCBvZiB0b3RhbCBwbG90Z3JvdXBzDQogICAgICAgIGJfcGxvdGdyb3VwW2tdIH4gZG5vcm0obXUucGxvdGdyb3VwW2tdLHRhdS5wbG90Z3JvdXApDQogICAgICAgIG11LnBsb3Rncm91cFtrXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzLCBsaW5lYXIgYW5kIHF1YWRyYXRpYyB0ZXJtDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogdGVtcGpqYS50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBqamEueDIgKiAodGVtcGpqYS50b3Rba11eMikgKyANCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54ICogdGVtcGNvbnQudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wY29udC54MiAqICh0ZW1wY29udC50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54ICogcHJlY2lwamphLnRvdFtrXSAjICsgDQogICAgICAgICAgICAgICAgICAgICMgYi5wcmVjaXBqamEueDIgKiAocHJlY2lwamphLnRvdFtrXV4yKSANCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgICAjIGFkZCBwcmVkaWN0ZWQgdmFsdWVzIChkZXJpdmVkIHBhcmFtZXRlcnMpDQogICAgICBmb3IgKG0gaW4gMTpOeGhhdCl7DQogICAgICAgIHBoYXRfZ3JhbWlub2lkX2NvdmVyW21dIDwtIGludGVyY2VwdCArIGIuZ3JhbWluX2NvdiAqIHhoYXRfZ3JhbWlub2lkX2NvdmVyW21dDQogICAgICAgIHBoYXRfc3JpW21dIDwtIGludGVyY2VwdCArIGIuc3JpICogeGhhdF9zcmlbbV0NCiAgICAgICAgcGhhdF90cmlbbV0gPC0gaW50ZXJjZXB0ICsgYi50cmkgKiB4aGF0X3RyaVttXQ0KICAgICAgICBwaGF0X3Rjd3NbbV0gPC0gaW50ZXJjZXB0ICsgYi50Y3dzICogeGhhdF90Y3dzW21dDQogICAgICAgIHBoYXRfdGVtcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSAjICsgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKQ0KICAgICAgICBwaGF0X3RlbXBjb250W21dIDwtIGludGVyY2VwdCArIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gIyArIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnByZWNpcGpqYS54ICogeGhhdF9wcmVjaXBqamFbbV0gIyArIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICANCiAgICAgICAgZm9yIChwIGluIDE6TnhoYXQyKXsNCiAgICAgICAgICBwaGF0X3RlbXBYbW9pc3RbbSxwXSA8LSBpbnRlcmNlcHQgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHhoYXRfdGVtcGpqYVttXSAqIHhoYXRfdGN3czJbcF0gIyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHhoYXRfdGVtcGpqYVttXV4yKSAqIHhoYXRfdGN3czJbcF0NCiAgICAgICAgfQ0KICAgICAgfQ0KDQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuQWxsU2hyMi5qYWdzIikpDQoNCiMgc3BlY2lmeSBuZXcgc2V0IG9mIHBhcmFtZXRlcnMNCnBhcmFtc19BbGxTaHIyIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgImIudGVtcGpqYS54IiwgIyAiYi50ZW1wamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgImIucHJlY2lwamphLngiLCAjICJiLnByZWNpcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgImIuZ3JhbWluX2NvdiIsDQogICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAiYi50cmkiLA0KICAgICAgICAgICAgICAgICAgICJiLnRjd3MiLA0KICAgICAgICAgICAgICAgICAgICJiX3Bsb3Rncm91cFsxXSIsImJfcGxvdGdyb3VwWzJdIiwiYl9wbG90Z3JvdXBbM10iLCJiX3Bsb3Rncm91cFs2M10iLA0KICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICJwaGF0X2dyYW1pbm9pZF9jb3ZlciIsIA0KICAgICAgICAgICAgICAgICAgICJwaGF0X3NyaSIsICJwaGF0X3Rjd3MiLCAicGhhdF90cmkiLCANCiAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wamphIiwgInBoYXRfdGVtcGNvbnQiLCAicGhhdF9wcmVjaXBqamEiLA0KICAgICAgICAgICAgICAgICAgICJwaGF0X3RlbXBYbW9pc3QiKQ0KDQojIHJ1biBtb2RlbA0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbFNocjIgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLkFsbFNoci5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX0FsbFNocjIsICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LkFsbFNocjIuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikgDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsU2hyMikgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsU2hyMiA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsU2hyMiRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsU2hyMiksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5BbGxTaHIyIDwtIGRhdGEuZnJhbWUocTUgPSBOQSwgcTk1ID0gTkEsIHBhcmFtID0gTkEpDQpmb3IgKHBhcmFtIGluIDE6KGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsU2hyMiRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5BbGxTaHIyW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsU2hyMiRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5BbGxTaHIyW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxTaHIyJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LkFsbFNocjIgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsU2hyMiAlPiUgDQogIGxlZnRfam9pbihjaV85MC5BbGxTaHIyLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQpzYXZlKGNvZWZmLnNocnViX2dyYWRpZW50LkFsbFNocjIsIGZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dHMiLCAiZ3JvdXBzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X0FsbFNocjIuUmRhdGEiKSkNCg0KKGVmZmVjdF9zaXplX3Bsb3QuQWxsU2hyMiA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxTaHIyLCB0aXRsZV9zdHJpbmcgPSAiYWxsIHNocnVicyIsIHBsb3Rfd2lkdGggPSA3LjUpKQ0KYGBgDQoNCiogKipwb3NpdGl2ZSByZXNwb25zZSB0byBUQyB3ZXRuZXNzLCBuZWdhdGl2ZSByZXNwb25zZSB0byBncmFtaW5vaWQgY292ZXIgKHNpZy4pKioNCiogcG9zaXRpdmUgcmVzcG9uc2UgdG8gcHJlY2lwaXRhdGlvbiBhbmQgc29sYXIgcmFkaWF0aW9uLCBuZWdhdGl2ZSB0byB0ZXJyYWluIGhldGVyb2dlbmVpdHkgKG4ucy4pDQoNCjxicj4NCg0KIyMjICpFdmVyZ3JlZW4gc2hydWJzKg0KYGBge3J9DQojIHJ1biBtb2RlbA0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbEV2ZSA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuQWxsRXZlLmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXNfZ3JvdXBzLCAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5ncm91cHMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikgDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRXZlKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LkFsbEV2ZSA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRXZlJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQogICMgbXV0YXRlKHBhcmFtID0gYXMudmVjdG9yKHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxFdmUpLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuQWxsRXZlIDwtIGRhdGEuZnJhbWUocTUgPSBOQSwgcTk1ID0gTkEsIHBhcmFtID0gTkEpDQpmb3IgKHBhcmFtIGluIDE6KGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRXZlJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLkFsbEV2ZVtwYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbEV2ZSRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5BbGxFdmVbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbEV2ZSRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxFdmUgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsRXZlICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLkFsbEV2ZSwgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0Kc2F2ZShjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxFdmUsIGZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dHMiLCAiZ3JvdXBzX3Rjd3MiLCAiZmlyc3RfcnVuc19jb252ZXJnZWQiLCAibW9kZWxfb3V0cHV0X0FsbEV2ZS5SZGF0YSIpKQ0KDQooZWZmZWN0X3NpemVfcGxvdC5BbGxFdmUgPC0gbW9kZWxfcGxvdF9zaWdfZnVuY3Rpb24oY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsRXZlLCB0aXRsZV9zdHJpbmcgPSAiZXZlcmdyZWVuIHNocnVicyIsIHBsb3Rfd2lkdGggPSAxMC41KSkNCmBgYA0KDQoqICoqdW5pbW9kYWwgcmVsYXRpb25zaGlwIHdpdGggdGVtcGVyYXR1cmUsIHBvc2l0aXZlIHdpdGggVEMgd2V0bmVzcywgbmVnYXRpdmUgd2l0aCBncmFtaW5vaWQgY292ZXIgKHNpZy4pKioNCiogc2xpZ2h0bHkgcG9zaXRpdmUgcmVzcG9uc2UgdG8gc29sYXIgcmFkaWF0aW9uLCBzbGlnaHRseSB1bmltb2RhbCByZWxhdGlvbnNoaXAgd2l0aCBwcmVjaXBpdGF0aW9uIChuLnMuKQ0KDQo8YnI+DQoNCmBgYHtyfQ0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQogICAgDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmdyYW1pbl9jb3YgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnNyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudHJpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50Y3dzIH4gZG5vcm0oMCwgMC4wMDAxKQ0KDQogICAgICBzaWdtYS5wbG90IH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdCA8LSAxLyhzaWdtYS5wbG90ICogc2lnbWEucGxvdCkNCiAgICAgIA0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcGNvbnQueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgYi50ZW1wWHRjd3MgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcFh0Y3dzMiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICANCiAgICAjIHBsb3QgbGV2ZWwNCg0KICAgICAgZm9yIChpIGluIDE6Tl9wbG90cyl7IA0KICAgICAgICBjb3YudG90W2ldIH4gZGxub3JtKG11LnBsb3RbaV0sIHRhdS5wbG90KQ0KICAgICAgICBsb2cobXUucGxvdFtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLnRvdFtpXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5ncmFtaW5fY292ICogZ3JhbWluX2Nvdi50b3RbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MudG90W2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEudG90LnBsb3RbaV0gKiB0Y3dzLnRvdFtpXSArICAgICAgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3czIgKiAodGVtcGpqYS50b3QucGxvdFtpXV4yKSAqIHRjd3MudG90W2ldICsgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS50b3RbaV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkudG90W2ldDQogICAgICB9DQoNCg0KICAgICMgcGxvdCBncm91cCBsZXZlbA0KICAgIA0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBjb250LngyICogKHRlbXBjb250LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiBwcmVjaXBqamEudG90W2tdICMgKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpIA0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAgICMgYWRkIHByZWRpY3RlZCB2YWx1ZXMgKGRlcml2ZWQgcGFyYW1ldGVycykNCiAgICAgIGZvciAobSBpbiAxOk54aGF0KXsNCiAgICAgICAgcGhhdF9ncmFtaW5vaWRfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5ncmFtaW5fY292ICogeGhhdF9ncmFtaW5vaWRfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zcmlbbV0gPC0gaW50ZXJjZXB0ICsgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnRyaSAqIHhoYXRfdHJpW21dDQogICAgICAgIHBoYXRfdGN3c1ttXSA8LSBpbnRlcmNlcHQgKyBiLnRjd3MgKiB4aGF0X3Rjd3NbbV0NCiAgICAgICAgcGhhdF90ZW1wamphW21dIDwtIGludGVyY2VwdCArIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICsgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKQ0KICAgICAgICBwaGF0X3RlbXBjb250W21dIDwtIGludGVyY2VwdCArIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gIyArIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnByZWNpcGpqYS54ICogeGhhdF9wcmVjaXBqamFbbV0gIyArIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICANCiAgICAgICAgZm9yIChwIGluIDE6TnhoYXQyKXsNCiAgICAgICAgICBwaGF0X3RlbXBYbW9pc3RbbSxwXSA8LSBpbnRlcmNlcHQgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamFbbV1eMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRjd3MgKiB4aGF0X3Rjd3MyW3BdICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MgKiB4aGF0X3RlbXBqamFbbV0gKiB4aGF0X3Rjd3MyW3BdICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MyICogKHhoYXRfdGVtcGpqYVttXV4yKSAqIHhoYXRfdGN3czJbcF0NCiAgICAgICAgfQ0KICAgICAgfQ0KDQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuQWxsRXZlMi5qYWdzIikpDQoNCiMgc3BlY2lmeSBuZXcgc2V0IG9mIHBhcmFtZXRlcnMNCnBhcmFtc19BbGxFdmUyIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgImIudGVtcGNvbnQueCIsICMgImIudGVtcGNvbnQueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLmdyYW1pbl9jb3YiLA0KICAgICAgICAgICAgICAgICAgICJiLnNyaSIsDQogICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAiYi50Y3dzIiwNCiAgICAgICAgICAgICAgICAgICAiYl9wbG90Z3JvdXBbMV0iLCJiX3Bsb3Rncm91cFsyXSIsImJfcGxvdGdyb3VwWzNdIiwiYl9wbG90Z3JvdXBbNjNdIiwNCiAgICAgICAgICAgICAgICAgICAic2lnbWEucGxvdGdyb3VwIiwNCiAgICAgICAgICAgICAgICAgICAicGhhdF9ncmFtaW5vaWRfY292ZXIiLCANCiAgICAgICAgICAgICAgICAgICAicGhhdF9zcmkiLCAicGhhdF90Y3dzIiwgInBoYXRfdHJpIiwgDQogICAgICAgICAgICAgICAgICAgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIiwNCiAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wWG1vaXN0IikNCg0KIyBydW4gbW9kZWwNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxFdmUyIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5BbGxFdmUuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc19BbGxFdmUyLCAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5BbGxFdmUyLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpIA0KDQojIHBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbFNocjIpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsRXZlMiA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRXZlMiRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsRXZlKSwiW1tdIixmaXhlZD1GQUxTRSksICJbIiwgMSkpKSAjJT4lIHByaW50DQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLkFsbEV2ZTIgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxFdmUyJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLkFsbEV2ZTJbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxFdmUyJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLkFsbEV2ZTJbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbEV2ZTIkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsRXZlMiA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxFdmUyICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLkFsbEV2ZTIsIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCnNhdmUoY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsRXZlMiwgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJncm91cHNfdGN3cyIsICJtb2RlbF9vdXRwdXRfQWxsRXZlMi5SZGF0YSIpKQ0KDQooZWZmZWN0X3NpemVfcGxvdC5BbGxFdmUyIDwtIG1vZGVsX3Bsb3Rfc2lnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkFsbEV2ZTIsIHRpdGxlX3N0cmluZyA9ICJldmVyZ3JlZW4gc2hydWJzIiwgcGxvdF93aWR0aCA9IDguNSkpDQpgYGANCiogKip1bmltb2RhbCByZXNwb25zZSB0byB0ZW1wZXJhdHVyZSwgbmVnYXRpdmUgcmVzcG9uc2UgdG8gZ3JhbWlub2lkIGNvdmVyIGFuZCB0ZW1wLiB2YXJpYWJpbGl0eSwgcG9zaXRpdmUgcmVsYXRpb25zaGlwIHdpdGggVEN3ZXRuZXNzIChzaWcuKSoqDQoqIHNsaWdodGx5IHBvc2l0aXZlIHJlc3BvbnNlIHRvIHNvbGFyIHJhZGlhdGlvbiAobi5zLikNCg0KPGJyPg0KDQojIyMgKkRlY2lkdW91cyBzaHJ1YnMqDQpgYGB7cn0NCiMgcnVuIG1vZGVsDQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRGVjIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5BbGxEZWMuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc19ncm91cHMsICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50Lmdyb3Vwcy5qYWdzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY2hhaW5zID0gMywgICAgICAgICAgICAgICAgICAgICAgICMgbm8uIE1hcmtvdiBjaGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLml0ZXIgPSAxMDAwMDAsIG4uYnVybmluID0gNzAwMDAsICAjIG5vLiBpdGVyYXRpb25zICYgYnVybi1pbiBmcmFjdGlvbiBwZXIgY2hhaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnRoaW4gPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaW5uaW5nIHJhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESUMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAjIGRvIG5vdCBjb21wdXRlIGRldmlhbmNlLCBwRCwgYW5kIERJQw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcuZGlyZWN0b3J5ID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MuYmFyID0gInRleHQiKSANCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuQWxsRGVjIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LkFsbERlYyksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5BbGxEZWMgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuQWxsRGVjW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRGVjJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLkFsbERlY1twYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRGVjJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LkFsbERlYyA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuQWxsRGVjLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQpzYXZlKGNvZWZmLnNocnViX2dyYWRpZW50LkFsbERlYywgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJncm91cHNfdGN3cyIsICJmaXJzdF9ydW5zX2NvbnZlcmdlZCIsICJtb2RlbF9vdXRwdXRfQWxsRGVjLlJkYXRhIikpDQoNCihlZmZlY3Rfc2l6ZV9wbG90LkFsbERlYyA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMsIHRpdGxlX3N0cmluZyA9ICJkZWNpZHVvdXMgc2hydWJzIiwgcGxvdF93aWR0aCA9IDEwLjUpKQ0KYGBgDQoNCiogKipwb3NpdGl2ZS91bmltb2RhbCByZXNwb25zZSB0byB0ZW1wLiB2YXJpYWJpbGl0eSwgbmVnYXRpdmUgcmVzcG9uc2UgdG8gZ3JhbWlub2lkIGNvdmVyIChzaWcuKSoqDQoqICpwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBzb2xhciByYWRpYXRpb24sIHdldG5lc3M7IG5lZ2F0aXZlIHdpdGggdGVycmFpbiBoZXRlcm9nZW5laXR5IChtLnMuKSoNCg0KPGJyPg0KDQpgYGB7cn0NCndyaXRlKCINCiAgDQogIG1vZGVsew0KICAgIA0KICAgICMgcHJpb3JzDQogICAgICANCiAgICAgIGludGVyY2VwdCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIA0KICAgICAgYi5ncmFtaW5fY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zcmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudGN3cyB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdCB+IGR1bmlmKDAsMTAwKQ0KICAgICAgdGF1LnBsb3QgPC0gMS8oc2lnbWEucGxvdCAqIHNpZ21hLnBsb3QpDQogICAgICANCiAgICAgIHNpZ21hLnBsb3Rncm91cCB+IGR1bmlmKDAsMTAwKQ0KICAgICAgdGF1LnBsb3Rncm91cCA8LSAxLyhzaWdtYS5wbG90Z3JvdXAgKiBzaWdtYS5wbG90Z3JvdXApDQogICAgICANCiAgICAgIGIudGVtcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBjb250LngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnByZWNpcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIucHJlY2lwamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIGIudGVtcFh0Y3dzIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBYdGN3czIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgDQogICAgIyBwbG90IGxldmVsDQoNCiAgICAgIGZvciAoaSBpbiAxOk5fcGxvdHMpeyANCiAgICAgICAgY292LnRvdFtpXSB+IGRsbm9ybShtdS5wbG90W2ldLCB0YXUucGxvdCkNCiAgICAgICAgbG9nKG11LnBsb3RbaV0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC50b3RbaV1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuZ3JhbWluX2NvdiAqIGdyYW1pbl9jb3YudG90W2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRjd3MgKiB0Y3dzLnRvdFtpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MgKiB0ZW1wamphLnRvdC5wbG90W2ldICogdGN3cy50b3RbaV0gKyAgICAgICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBYdGN3czIgKiAodGVtcGpqYS50b3QucGxvdFtpXV4yKSAqIHRjd3MudG90W2ldICsgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS50b3RbaV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkudG90W2ldDQogICAgICB9DQoNCg0KICAgICMgcGxvdCBncm91cCBsZXZlbA0KICAgIA0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHRlbXBqamEudG90W2tdXjIpICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHRlbXBjb250LnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LngyICogKHRlbXBjb250LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiBwcmVjaXBqamEudG90W2tdICMgKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpIA0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAgICMgYWRkIHByZWRpY3RlZCB2YWx1ZXMgKGRlcml2ZWQgcGFyYW1ldGVycykNCiAgICAgIGZvciAobSBpbiAxOk54aGF0KXsNCiAgICAgICAgcGhhdF9ncmFtaW5vaWRfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5ncmFtaW5fY292ICogeGhhdF9ncmFtaW5vaWRfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zcmlbbV0gPC0gaW50ZXJjZXB0ICsgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnRyaSAqIHhoYXRfdHJpW21dDQogICAgICAgIHBoYXRfdGN3c1ttXSA8LSBpbnRlcmNlcHQgKyBiLnRjd3MgKiB4aGF0X3Rjd3NbbV0NCiAgICAgICAgcGhhdF90ZW1wamphW21dIDwtIGludGVyY2VwdCArIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICMgKyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphW21dXjIpDQogICAgICAgIHBoYXRfdGVtcGNvbnRbbV0gPC0gaW50ZXJjZXB0ICsgYi50ZW1wY29udC54ICogeGhhdF90ZW1wY29udFttXSArIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnByZWNpcGpqYS54ICogeGhhdF9wcmVjaXBqamFbbV0gIyArIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICANCiAgICAgICAgZm9yIChwIGluIDE6TnhoYXQyKXsNCiAgICAgICAgICBwaGF0X3RlbXBYbW9pc3RbbSxwXSA8LSBpbnRlcmNlcHQgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHhoYXRfdGVtcGpqYVttXSAqIHhoYXRfdGN3czJbcF0gIyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHhoYXRfdGVtcGpqYVttXV4yKSAqIHhoYXRfdGN3czJbcF0NCiAgICAgICAgfQ0KICAgICAgfQ0KDQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuQWxsRGVjMi5qYWdzIikpDQoNCiMgc3BlY2lmeSBuZXcgc2V0IG9mIHBhcmFtZXRlcnMNCnBhcmFtc19BbGxEZWMyIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgImIudGVtcGpqYS54IiwgIyAiYi50ZW1wamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgImIudGVtcGNvbnQueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLmdyYW1pbl9jb3YiLA0KICAgICAgICAgICAgICAgICAgICJiLnNyaSIsDQogICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAiYi50Y3dzIiwNCiAgICAgICAgICAgICAgICAgICAiYl9wbG90Z3JvdXBbMV0iLCJiX3Bsb3Rncm91cFsyXSIsImJfcGxvdGdyb3VwWzNdIiwiYl9wbG90Z3JvdXBbNjNdIiwNCiAgICAgICAgICAgICAgICAgICAic2lnbWEucGxvdGdyb3VwIiwNCiAgICAgICAgICAgICAgICAgICAicGhhdF9ncmFtaW5vaWRfY292ZXIiLCANCiAgICAgICAgICAgICAgICAgICAicGhhdF9zcmkiLCAicGhhdF90Y3dzIiwgInBoYXRfdHJpIiwgDQogICAgICAgICAgICAgICAgICAgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIiwNCiAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wWG1vaXN0IikNCg0KIyBydW4gbW9kZWwNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMyIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5BbGxEZWMuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc19BbGxEZWMyLCAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5BbGxEZWMyLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpIA0KDQojIHBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbERlYzIpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LkFsbERlYzIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbERlYzIkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LkFsbERlYzIpLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuQWxsRGVjMiA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbERlYzIkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuQWxsRGVjMltwYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkFsbERlYzIkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuQWxsRGVjMltwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQWxsRGVjMiRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMyIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LkFsbERlYzIgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuQWxsRGVjMiwgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0Kc2F2ZShjb2VmZi5zaHJ1Yl9ncmFkaWVudC5BbGxEZWMyLCBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgImdyb3Vwc190Y3dzIiwgIm1vZGVsX291dHB1dF9BbGxEZWMyLlJkYXRhIikpDQoNCihlZmZlY3Rfc2l6ZV9wbG90LkFsbERlYzIgPC0gbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkFsbERlYzIsIHRpdGxlX3N0cmluZyA9ICJkZWNpZHVvdXMgc2hydWJzIiwgcGxvdF93aWR0aCA9IDguNSkpDQpgYGANCiogKipwb3NpdGl2ZS91bmltb2RhbCByZWxhdGlvbnNoaXAgd2l0aCB0ZW1wZXJhdHVyZSB2YXJpYWJpbGl0eSwgbmVnYXRpdmUgcmVsYXRpb25zaGlwIHdpdGggZ3JhbWlub2lkIGNvdmVyLCBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBUQyB3ZXRuZXNzIGFuZCBzdW1tZXIgdGVtcGVyYXR1cmUgKHNpZy4pKioNCiogKnBvc2l0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIHNvbGFyIHJhZGlhdGlvbiwgbmVnYXRpdmUgd2l0aCB0ZXJyYWluIGhldGVyb2dlbmVpdHkgKG0ucy4pKg0KDQo8YnI+DQoNCiMjIyBTcGVjaWVzDQojIyMgPiBzcGVjaWVzOiBhc3NlbWJsaW5nIGRhdGEgZm9yIG1vZGVsIGlucHV0IGluIGxpc3RzDQoNCmBgYHtyfQ0KIyBCZXROYW4gLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5CZXROYW4uZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gQmV0TmFuLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IEJldE5hbi5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBCZXROYW4uZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gQmV0TmFuLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gQmV0TmFuLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IEJldE5hbi5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBCZXROYW4uZGlzJEJldE5hbl9zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gQmV0TmFuLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gQmV0TmFuLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhCZXROYW4uZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IEJldE5hbi5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IEJldE5hbi5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IEJldE5hbi5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IEJldE5hbi5jb250JHNyaUMsDQogIHRyaS5jb250ID0gQmV0TmFuLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gQmV0TmFuLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gQmV0TmFuLmNvbnQkQmV0TmFuX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gQmV0TmFuLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBCZXROYW4uY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KEJldE5hbi5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gQmV0TmFuLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IEJldE5hbi50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gQmV0TmFuLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoQmV0TmFuLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoQmV0TmFuLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihCZXROYW4udG90JEJldE5hbl9zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChCZXROYW4udG90JEJldE5hbl9zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihCZXROYW4udG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChCZXROYW4udG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihCZXROYW4udG90JHNyaUMpLCB0byA9IG1heChCZXROYW4udG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihCZXROYW4udG90JHRyaUMpLCB0byA9IG1heChCZXROYW4udG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCR0Y3dzQyksIHRvID0gbWF4KEJldE5hbi50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KEJldE5hbi50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihCZXROYW4udG90JHByZWNpcGpqYUMpLCB0byA9IG1heChCZXROYW4udG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKEJldE5hbi50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoQmV0TmFuLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoQmV0TmFuLnRvdCR0Y3dzQywwLjA1KSxxdWFudGlsZShCZXROYW4udG90JHRjd3NDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5CZXROYW4uZGF0YSkNCg0KIyBDYXNUZXQgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5DYXNUZXQuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gQ2FzVGV0LmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IENhc1RldC5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBDYXNUZXQuZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gQ2FzVGV0LmRpcyRzcmlDLA0KICB0cmkuZGlzID0gQ2FzVGV0LmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IENhc1RldC5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBDYXNUZXQuZGlzJENhc1RldF9zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gQ2FzVGV0LmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gQ2FzVGV0LmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhDYXNUZXQuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IENhc1RldC5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IENhc1RldC5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IENhc1RldC5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IENhc1RldC5jb250JHNyaUMsDQogIHRyaS5jb250ID0gQ2FzVGV0LmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gQ2FzVGV0LmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gQ2FzVGV0LmNvbnQkQ2FzVGV0X3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gQ2FzVGV0LmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBDYXNUZXQuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KENhc1RldC5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gQ2FzVGV0LnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IENhc1RldC50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gQ2FzVGV0LnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoQ2FzVGV0LnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oQ2FzVGV0LnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoQ2FzVGV0LnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JENhc1RldF9zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChDYXNUZXQudG90JENhc1RldF9zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChDYXNUZXQudG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JHNyaUMpLCB0byA9IG1heChDYXNUZXQudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JHRyaUMpLCB0byA9IG1heChDYXNUZXQudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oQ2FzVGV0LnRvdCR0Y3dzQyksIHRvID0gbWF4KENhc1RldC50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oQ2FzVGV0LnRvdCR0ZW1wamphQyksIHRvID0gbWF4KENhc1RldC50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JHByZWNpcGpqYUMpLCB0byA9IG1heChDYXNUZXQudG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKENhc1RldC50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoQ2FzVGV0LnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoQ2FzVGV0LnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShDYXNUZXQudG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5DYXNUZXQuZGF0YSkNCg0KIyBFbXBOaWcgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5FbXBOaWcuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gRW1wTmlnLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IEVtcE5pZy5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBFbXBOaWcuZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gRW1wTmlnLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gRW1wTmlnLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IEVtcE5pZy5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBFbXBOaWcuZGlzJEVtcE5pZ19zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gRW1wTmlnLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gRW1wTmlnLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhFbXBOaWcuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IEVtcE5pZy5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IEVtcE5pZy5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IEVtcE5pZy5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IEVtcE5pZy5jb250JHNyaUMsDQogIHRyaS5jb250ID0gRW1wTmlnLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gRW1wTmlnLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gRW1wTmlnLmNvbnQkRW1wTmlnX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gRW1wTmlnLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBFbXBOaWcuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KEVtcE5pZy5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gRW1wTmlnLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IEVtcE5pZy50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gRW1wTmlnLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoRW1wTmlnLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oRW1wTmlnLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoRW1wTmlnLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihFbXBOaWcudG90JEVtcE5pZ19zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChFbXBOaWcudG90JEVtcE5pZ19zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihFbXBOaWcudG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChFbXBOaWcudG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihFbXBOaWcudG90JHNyaUMpLCB0byA9IG1heChFbXBOaWcudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihFbXBOaWcudG90JHRyaUMpLCB0byA9IG1heChFbXBOaWcudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oRW1wTmlnLnRvdCR0Y3dzQyksIHRvID0gbWF4KEVtcE5pZy50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oRW1wTmlnLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KEVtcE5pZy50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihFbXBOaWcudG90JHByZWNpcGpqYUMpLCB0byA9IG1heChFbXBOaWcudG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKEVtcE5pZy50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoRW1wTmlnLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoRW1wTmlnLnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShFbXBOaWcudG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5FbXBOaWcuZGF0YSkNCg0KIyBQaHlDYWUgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5QaHlDYWUuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gUGh5Q2FlLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFBoeUNhZS5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBQaHlDYWUuZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gUGh5Q2FlLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gUGh5Q2FlLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IFBoeUNhZS5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBQaHlDYWUuZGlzJFBoeUNhZV9zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gUGh5Q2FlLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gUGh5Q2FlLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhQaHlDYWUuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFBoeUNhZS5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFBoeUNhZS5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IFBoeUNhZS5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IFBoeUNhZS5jb250JHNyaUMsDQogIHRyaS5jb250ID0gUGh5Q2FlLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gUGh5Q2FlLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gUGh5Q2FlLmNvbnQkUGh5Q2FlX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gUGh5Q2FlLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBQaHlDYWUuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFBoeUNhZS5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gUGh5Q2FlLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IFBoeUNhZS50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gUGh5Q2FlLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoUGh5Q2FlLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoUGh5Q2FlLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihQaHlDYWUudG90JFBoeUNhZV9zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChQaHlDYWUudG90JFBoeUNhZV9zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihQaHlDYWUudG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChQaHlDYWUudG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihQaHlDYWUudG90JHNyaUMpLCB0byA9IG1heChQaHlDYWUudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihQaHlDYWUudG90JHRyaUMpLCB0byA9IG1heChQaHlDYWUudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCR0Y3dzQyksIHRvID0gbWF4KFBoeUNhZS50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KFBoeUNhZS50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihQaHlDYWUudG90JHByZWNpcGpqYUMpLCB0byA9IG1heChQaHlDYWUudG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFBoeUNhZS50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoUGh5Q2FlLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoUGh5Q2FlLnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShQaHlDYWUudG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5QaHlDYWUuZGF0YSkNCg0KIyBSaG9Hcm8gLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5SaG9Hcm8uZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gUmhvR3JvLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFJob0dyby5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBSaG9Hcm8uZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gUmhvR3JvLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gUmhvR3JvLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IFJob0dyby5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBSaG9Hcm8uZGlzJFJob0dyb19zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gUmhvR3JvLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gUmhvR3JvLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhSaG9Hcm8uZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFJob0dyby5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFJob0dyby5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IFJob0dyby5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IFJob0dyby5jb250JHNyaUMsDQogIHRyaS5jb250ID0gUmhvR3JvLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gUmhvR3JvLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gUmhvR3JvLmNvbnQkUmhvR3JvX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gUmhvR3JvLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBSaG9Hcm8uY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFJob0dyby5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gUmhvR3JvLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IFJob0dyby50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gUmhvR3JvLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoUmhvR3JvLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oUmhvR3JvLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoUmhvR3JvLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JFJob0dyb19zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChSaG9Hcm8udG90JFJob0dyb19zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChSaG9Hcm8udG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JHNyaUMpLCB0byA9IG1heChSaG9Hcm8udG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JHRyaUMpLCB0byA9IG1heChSaG9Hcm8udG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oUmhvR3JvLnRvdCR0Y3dzQyksIHRvID0gbWF4KFJob0dyby50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oUmhvR3JvLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KFJob0dyby50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JHByZWNpcGpqYUMpLCB0byA9IG1heChSaG9Hcm8udG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFJob0dyby50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoUmhvR3JvLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoUmhvR3JvLnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShSaG9Hcm8udG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5SaG9Hcm8uZGF0YSkNCg0KIyBSaG9Ub20gLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5SaG9Ub20uZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gUmhvVG9tLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFJob1RvbS5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBSaG9Ub20uZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gUmhvVG9tLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gUmhvVG9tLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IFJob1RvbS5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBSaG9Ub20uZGlzJFJob1RvbV9zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gUmhvVG9tLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gUmhvVG9tLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhSaG9Ub20uZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFJob1RvbS5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFJob1RvbS5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IFJob1RvbS5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IFJob1RvbS5jb250JHNyaUMsDQogIHRyaS5jb250ID0gUmhvVG9tLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gUmhvVG9tLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gUmhvVG9tLmNvbnQkUmhvVG9tX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gUmhvVG9tLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBSaG9Ub20uY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFJob1RvbS5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gUmhvVG9tLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IFJob1RvbS50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gUmhvVG9tLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoUmhvVG9tLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oUmhvVG9tLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoUmhvVG9tLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihSaG9Ub20udG90JFJob1RvbV9zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChSaG9Ub20udG90JFJob1RvbV9zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihSaG9Ub20udG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChSaG9Ub20udG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihSaG9Ub20udG90JHNyaUMpLCB0byA9IG1heChSaG9Ub20udG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihSaG9Ub20udG90JHRyaUMpLCB0byA9IG1heChSaG9Ub20udG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oUmhvVG9tLnRvdCR0Y3dzQyksIHRvID0gbWF4KFJob1RvbS50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oUmhvVG9tLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KFJob1RvbS50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihSaG9Ub20udG90JHByZWNpcGpqYUMpLCB0byA9IG1heChSaG9Ub20udG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFJob1RvbS50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoUmhvVG9tLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoUmhvVG9tLnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShSaG9Ub20udG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5SaG9Ub20uZGF0YSkNCg0KIyBTYWxBcmMgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5TYWxBcmMuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gU2FsQXJjLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFNhbEFyYy5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBTYWxBcmMuZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gU2FsQXJjLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gU2FsQXJjLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IFNhbEFyYy5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBTYWxBcmMuZGlzJFNhbEFyY19zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gU2FsQXJjLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gU2FsQXJjLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhTYWxBcmMuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFNhbEFyYy5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFNhbEFyYy5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IFNhbEFyYy5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IFNhbEFyYy5jb250JHNyaUMsDQogIHRyaS5jb250ID0gU2FsQXJjLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gU2FsQXJjLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gU2FsQXJjLmNvbnQkU2FsQXJjX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gU2FsQXJjLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBTYWxBcmMuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFNhbEFyYy5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gU2FsQXJjLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IFNhbEFyYy50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gU2FsQXJjLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoU2FsQXJjLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoU2FsQXJjLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihTYWxBcmMudG90JFNhbEFyY19zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChTYWxBcmMudG90JFNhbEFyY19zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihTYWxBcmMudG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChTYWxBcmMudG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihTYWxBcmMudG90JHNyaUMpLCB0byA9IG1heChTYWxBcmMudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihTYWxBcmMudG90JHRyaUMpLCB0byA9IG1heChTYWxBcmMudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCR0Y3dzQyksIHRvID0gbWF4KFNhbEFyYy50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KFNhbEFyYy50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihTYWxBcmMudG90JHByZWNpcGpqYUMpLCB0byA9IG1heChTYWxBcmMudG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFNhbEFyYy50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoU2FsQXJjLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoU2FsQXJjLnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShTYWxBcmMudG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5TYWxBcmMuZGF0YSkNCg0KIyBTYWxHbGEgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5TYWxHbGEuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gU2FsR2xhLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFNhbEdsYS5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBTYWxHbGEuZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gU2FsR2xhLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gU2FsR2xhLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IFNhbEdsYS5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBTYWxHbGEuZGlzJFNhbEdsYV9zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gU2FsR2xhLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gU2FsR2xhLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhTYWxHbGEuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFNhbEdsYS5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFNhbEdsYS5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IFNhbEdsYS5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IFNhbEdsYS5jb250JHNyaUMsDQogIHRyaS5jb250ID0gU2FsR2xhLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gU2FsR2xhLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gU2FsR2xhLmNvbnQkU2FsR2xhX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gU2FsR2xhLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBTYWxHbGEuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFNhbEdsYS5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gU2FsR2xhLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IFNhbEdsYS50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gU2FsR2xhLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoU2FsR2xhLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oU2FsR2xhLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoU2FsR2xhLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JFNhbEdsYV9zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChTYWxHbGEudG90JFNhbEdsYV9zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChTYWxHbGEudG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JHNyaUMpLCB0byA9IG1heChTYWxHbGEudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JHRyaUMpLCB0byA9IG1heChTYWxHbGEudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oU2FsR2xhLnRvdCR0Y3dzQyksIHRvID0gbWF4KFNhbEdsYS50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oU2FsR2xhLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KFNhbEdsYS50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JHByZWNpcGpqYUMpLCB0byA9IG1heChTYWxHbGEudG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFNhbEdsYS50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoU2FsR2xhLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoU2FsR2xhLnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShTYWxHbGEudG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5TYWxHbGEuZGF0YSkNCg0KIyBWYWNVbGkgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5WYWNVbGkuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gVmFjVWxpLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFZhY1VsaS5kaXMkcGxvdGdyb3VwLk5VTSwNCiAgdGVtcGpqYS5kaXMgPSBWYWNVbGkuZGlzJHRlbXBqamFDLA0KICBzcmkuZGlzID0gVmFjVWxpLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gVmFjVWxpLmRpcyR0cmlDLA0KICB0Y3dzLmRpcyA9IFZhY1VsaS5kaXMkdGN3c0MsDQogIHNocnViX2Nvdi5kaXMgPSBWYWNVbGkuZGlzJFZhY1VsaV9zaHJ1Yl9jb3ZlckMsDQogIGdyYW1pbl9jb3YuZGlzID0gVmFjVWxpLmRpcyRncmFtaW5vaWRfY292ZXJDLA0KICBjb21wZXQuZGlzID0gVmFjVWxpLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhWYWNVbGkuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFZhY1VsaS5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFZhY1VsaS5jb250JHBsb3Rncm91cC5OVU0sDQogIHRlbXBqamEuY29udCA9IFZhY1VsaS5jb250JHRlbXBqamFDLA0KICBzcmkuY29udCA9IFZhY1VsaS5jb250JHNyaUMsDQogIHRyaS5jb250ID0gVmFjVWxpLmNvbnQkdHJpQywNCiAgdGN3cy5jb250ID0gVmFjVWxpLmNvbnQkdGN3c0MsDQogIHNocnViX2Nvdi5jb250ID0gVmFjVWxpLmNvbnQkVmFjVWxpX3NocnViX2NvdmVyQywNCiAgZ3JhbWluX2Nvdi5jb250ID0gVmFjVWxpLmNvbnQkZ3JhbWlub2lkX2NvdmVyQywNCiAgY29tcGV0LmNvbnQgPSBWYWNVbGkuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFZhY1VsaS5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gVmFjVWxpLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZSh0ZW1wamphLnRvdCA9IG1lYW4odGVtcGpqYUMpKSAlPiUgcHVsbCh0ZW1wamphLnRvdCksICMgb25lIHZhbHVlIHBlciB0WHBnDQogIHRlbXBjb250LnRvdCA9IFZhY1VsaS50b3QgJT4lIGdyb3VwX2J5KHBsb3Rncm91cC5OVU0pICU+JSBzdW1tYXJpc2UodGVtcGNvbnQudG90ID0gbWVhbih0ZW1wY29udEMpKSAlPiUgcHVsbCh0ZW1wY29udC50b3QpLA0KICBwcmVjaXBqamEudG90ID0gVmFjVWxpLnRvdCAlPiUgZ3JvdXBfYnkocGxvdGdyb3VwLk5VTSkgJT4lIHN1bW1hcmlzZShwcmVjaXBqamEudG90ID0gbWVhbihwcmVjaXBqamFDKSkgJT4lIHB1bGwocHJlY2lwamphLnRvdCksDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoVmFjVWxpLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oVmFjVWxpLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoVmFjVWxpLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc2hydWJfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihWYWNVbGkudG90JFZhY1VsaV9zaHJ1Yl9jb3ZlckMpLCB0byA9IG1heChWYWNVbGkudG90JFZhY1VsaV9zaHJ1Yl9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9ncmFtaW5vaWRfY292ZXIgPSBzZXEoZnJvbSA9IG1pbihWYWNVbGkudG90JGdyYW1pbm9pZF9jb3ZlckMpLCB0byA9IG1heChWYWNVbGkudG90JGdyYW1pbm9pZF9jb3ZlckMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihWYWNVbGkudG90JHNyaUMpLCB0byA9IG1heChWYWNVbGkudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihWYWNVbGkudG90JHRyaUMpLCB0byA9IG1heChWYWNVbGkudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90Y3dzID0gc2VxKGZyb20gPSBtaW4oVmFjVWxpLnRvdCR0Y3dzQyksIHRvID0gbWF4KFZhY1VsaS50b3QkdGN3c0MpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oVmFjVWxpLnRvdCR0ZW1wamphQyksIHRvID0gbWF4KFZhY1VsaS50b3QkdGVtcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihWYWNVbGkudG90JHByZWNpcGpqYUMpLCB0byA9IG1heChWYWNVbGkudG90JHByZWNpcGpqYUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFZhY1VsaS50b3QkdGVtcGNvbnRDKSwgdG8gPSBtYXgoVmFjVWxpLnRvdCR0ZW1wY29udEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGN3czIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoVmFjVWxpLnRvdCR0ZW1wamphQywwLjA1KSxxdWFudGlsZShWYWNVbGkudG90JHRlbXBqamFDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5WYWNVbGkuZGF0YSkNCg0KDQojICMgc2F2ZSBtb2RlbCBpbnB1dCBkYXRhDQpzYXZlKGxpc3QgPSBjKCJzaHJ1Yl9ncmFkaWVudF9qYWdzLkJldE5hbi5kYXRhIiwNCiAgICAgICAgICAgICAgInNocnViX2dyYWRpZW50X2phZ3MuQ2FzVGV0LmRhdGEiLA0KICAgICAgICAgICAgICAic2hydWJfZ3JhZGllbnRfamFncy5FbXBOaWcuZGF0YSIsDQogICAgICAgICAgICAgICJzaHJ1Yl9ncmFkaWVudF9qYWdzLlBoeUNhZS5kYXRhIiwNCiAgICAgICAgICAgICAgInNocnViX2dyYWRpZW50X2phZ3MuUmhvR3JvLmRhdGEiLA0KICAgICAgICAgICAgICAic2hydWJfZ3JhZGllbnRfamFncy5SaG9Ub20uZGF0YSIsDQogICAgICAgICAgICAgICJzaHJ1Yl9ncmFkaWVudF9qYWdzLlNhbEFyYy5kYXRhIiwNCiAgICAgICAgICAgICAgInNocnViX2dyYWRpZW50X2phZ3MuU2FsR2xhLmRhdGEiLA0KICAgICAgICAgICAgICAic2hydWJfZ3JhZGllbnRfamFncy5WYWNVbGkuZGF0YSIpLA0KICAgICBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9pbnB1dF9kYXRhX3Rjd3MiLCAic2hydWJfZ3JhZGllbnRfamFncy5zcGVjaWVzZGF0YS5SZGF0YSIpKQ0KYGBgDQoNCiMjIyA+IHNwZWNpZnlpbmcgbW9kZWwNCmBgYHtyfQ0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQogICAgDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmNvbXBldCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc2hydWJfY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5ncmFtaW5fY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zcmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudGN3cyB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBjb250LngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnByZWNpcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnByZWNpcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICBiLnRlbXBYdGN3cyB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wWHRjd3MyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIHBoaSB+IGRnYW1tYSgwLjEsIDAuMSkNCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBkaXNjcmV0ZSBwYXJ0DQoNCiAgICAgIGZvciAoaSBpbiAxOk5fZGlzY3JldGUpeyANCiAgICAgICAgY292LmRpc1tpXSB+IGRiZXJuKG11W2ldKQ0KICAgICAgICBsb2dpdChtdVtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmRpc1tpXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5jb21wZXQgKiBjb21wZXQuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNocnViX2NvdiAqIHNocnViX2Nvdi5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuZ3JhbWluX2NvdiAqIGdyYW1pbl9jb3YuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEuZGlzW2ldICogdGN3cy5kaXNbaV0gKyAgICAgICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MyICogKHRlbXBqamEuZGlzW2ldXjIpICogdGN3cy5kaXNbaV0gKyAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS5kaXNbaV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkuZGlzW2ldDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICMgTElLRUxJSE9PRCBmb3IgY29udGludW91cyBwYXJ0DQoNCiAgICAgIGZvciAoaiBpbiAxOk5fY29udCl7DQogICAgICAgIGNvdi5jb250W2pdIH4gZGJldGEocFtqXSwgcVtqXSkNCiAgICAgICAgcFtqXSA8LSBtdTJbal0gKiBwaGkNCiAgICAgICAgcVtqXSA8LSAoMSAtIG11MltqXSkgKiBwaGkNCiAgICAgICAgbG9naXQobXUyW2pdKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuY29udFtqXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5jb21wZXQgKiBjb21wZXQuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNocnViX2NvdiAqIHNocnViX2Nvdi5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIuZ3JhbWluX2NvdiAqIGdyYW1pbl9jb3YuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEuY29udFtqXSAqIHRjd3MuY29udFtqXSArICAgICAgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3czIgKiAodGVtcGpqYS5jb250W2pdXjIpICogdGN3cy5jb250W2pdICsgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRjd3MgKiB0Y3dzLmNvbnRbal0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkuY29udFtqXQ0KICAgICAgfQ0KDQoNCiAgICAgIGZvciAoayBpbiAxOk5fcGxvdGdyb3Vwcyl7ICMgbGVuZ3RoIG9mIHRvdGFsIHBsb3Rncm91cHMNCiAgICAgICAgYl9wbG90Z3JvdXBba10gfiBkbm9ybShtdS5wbG90Z3JvdXBba10sdGF1LnBsb3Rncm91cCkNCiAgICAgICAgbXUucGxvdGdyb3VwW2tdIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIyBwbG90IGdyb3VwIGxldmVsIHByZWRpY3RvcnMsIGxpbmVhciBhbmQgcXVhZHJhdGljIHRlcm0NCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wamphLnggKiB0ZW1wamphLnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueDIgKiAodGVtcGpqYS50b3Rba11eMikgKyANCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54ICogdGVtcGNvbnQudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueDIgKiAodGVtcGNvbnQudG90W2tdXjIpICsNCiAgICAgICAgICAgICAgICAgICAgYi5wcmVjaXBqamEueCAqIHByZWNpcGpqYS50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgYi5wcmVjaXBqamEueDIgKiAocHJlY2lwamphLnRvdFtrXV4yKSANCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgICAjIGFkZCBwcmVkaWN0ZWQgdmFsdWVzIChkZXJpdmVkIHBhcmFtZXRlcnMpDQogICAgICBmb3IgKG0gaW4gMTpOeGhhdCl7DQogICAgICAgIHBoYXRfY29tcGV0W21dIDwtIGludGVyY2VwdCArIGIuY29tcGV0ICogeGhhdF9jb21wZXRbbV0NCiAgICAgICAgcGhhdF9ncmFtaW5vaWRfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5ncmFtaW5fY292ICogeGhhdF9ncmFtaW5vaWRfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zaHJ1Yl9jb3ZlclttXSA8LSBpbnRlcmNlcHQgKyBiLnNocnViX2NvdiAqIHhoYXRfc2hydWJfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zcmlbbV0gPC0gaW50ZXJjZXB0ICsgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnRyaSAqIHhoYXRfdHJpW21dDQogICAgICAgIHBoYXRfdGN3c1ttXSA8LSBpbnRlcmNlcHQgKyBiLnRjd3MgKiB4aGF0X3Rjd3NbbV0NCiAgICAgICAgcGhhdF90ZW1wamphW21dIDwtIGludGVyY2VwdCArIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICsgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKQ0KICAgICAgICBwaGF0X3RlbXBjb250W21dIDwtIGludGVyY2VwdCArIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gKyBiLnRlbXBjb250LngyICogKHhoYXRfdGVtcGNvbnRbbV1eMikNCiAgICAgICAgcGhhdF9wcmVjaXBqamFbbV0gPC0gaW50ZXJjZXB0ICsgYi5wcmVjaXBqamEueCAqIHhoYXRfcHJlY2lwamphW21dICsgYi5wcmVjaXBqamEueDIgKiAoeGhhdF9wcmVjaXBqamFbbV1eMikNCiAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcFhtb2lzdFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHhoYXRfdGVtcGpqYVttXSAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3czIgKiAoeGhhdF90ZW1wamphW21dXjIpICogeGhhdF90Y3dzMltwXQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KDQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuc3BlYy5qYWdzIikpDQpgYGANCg0KU3BlY2lmeSB0aGUgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQ6DQpgYGB7cn0NCnBhcmFtcyA8LSBjKCJpbnRlcmNlcHQiLA0KICAgICAgICAgICAgImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICAgICAgICAgICAiYi50ZW1wY29udC54IiwgImIudGVtcGNvbnQueDIiLA0KICAgICAgICAgICAgImIucHJlY2lwamphLngiLCAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgImIuY29tcGV0IiwNCiAgICAgICAgICAgICJiLnNocnViX2NvdiIsIA0KICAgICAgICAgICAgImIuZ3JhbWluX2NvdiIsDQogICAgICAgICAgICAiYi5zcmkiLA0KICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICJiLnRjd3MiLA0KICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAic2lnbWEucGxvdGdyb3VwIiwNCiAgICAgICAgICAgICJwaGkiLA0KICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc2hydWJfY292ZXIiLCAicGhhdF9ncmFtaW5vaWRfY292ZXIiLCANCiAgICAgICAgICAgICJwaGF0X3NyaSIsICJwaGF0X3Rjd3MiLCAicGhhdF90cmkiLCANCiAgICAgICAgICAgICJwaGF0X3RlbXBqamEiLCAicGhhdF90ZW1wY29udCIsICJwaGF0X3ByZWNpcGpqYSIsIA0KICAgICAgICAgICAgInBoYXRfdGVtcFhtb2lzdCIpDQpgYGANCg0KIyMjID4gcnVuICYgZXZhbHVhdGUgbW9kZWwNCjxicj4NCg0KIyMjICpCZXR1bGEgbmFuYSoNCmBgYHtyfQ0KIyBydW4gbW9kZWwNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4gPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLkJldE5hbi5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuc3BlYy5qYWdzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY2hhaW5zID0gMywgICAgICAgICAgICAgICAgICAgICAgICMgbm8uIE1hcmtvdiBjaGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLml0ZXIgPSAxMDAwMDAsIG4uYnVybmluID0gNzAwMDAsICAjIG5vLiBpdGVyYXRpb25zICYgYnVybi1pbiBmcmFjdGlvbiBwZXIgY2hhaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnRoaW4gPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaW5uaW5nIHJhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESUMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAjIGRvIG5vdCBjb21wdXRlIGRldmlhbmNlLCBwRCwgYW5kIERJQw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcuZGlyZWN0b3J5ID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MuYmFyID0gInRleHQiKSANCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4pICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuQmV0TmFuIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4kQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbiksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5CZXROYW4gPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4kQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuQmV0TmFuW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLkJldE5hbltwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbiA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4gJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuQmV0TmFuLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpDQoNCnNhdmUoY29lZmYuc2hydWJfZ3JhZGllbnQuQmV0TmFuLCBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgInNwZWNpZXNfdGN3cyIsICJmaXJzdF9ydW5zX2NvbnZlcmdlZCIsICJtb2RlbF9vdXRwdXRfQmV0TmFuLlJkYXRhIikpDQojIGxvYWQoZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgInNwZWNpZXNfdGN3cyIsICJmaXJzdF9ydW5zX2NvbnZlcmdlZCIsICJtb2RlbF9vdXRwdXRfQmV0TmFuLlJkYXRhIikpDQpwcmludChjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4pDQooZWZmZWN0X3NpemVfcGxvdC5CZXROYW4gPC0gbW9kZWxfcGxvdF9zaWdfZnVuY3Rpb24oY29lZmYuc2hydWJfZ3JhZGllbnQuQmV0TmFuLCB0aXRsZV9zdHJpbmcgPSAiQmV0dWxhIG5hbmEiLCBwbG90X3dpZHRoID0gMTIuNSkpDQpgYGANCg0KKiAqKnBvc2l0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIG1vcmUgY29uc2VydmF0aXZlIGNvbW11bml0aWVzLCBuZWdhdGl2ZSByZXNwb25zZSB0byBncmFtaW5vaWQgY292ZXIgKHNpZy4pKiogDQoqICp1bmltb2RhbCByZWxhdGlvbnNoaXAgd2l0aCB0ZW1wZXJhdHVyZSB2YXJpYWJpbGl0eSAobS5zLikqDQoNCjxicj4NCg0KQXMgbm9uZSBvZiB0aGUgcXVhZHJhdGljIHRlcm1zIGZvciBjbGltYXRpYyB2YXJpYWJsZXMgd2VyZSBzaWduaWZpY2FudCwgdGhleSB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgbW9kZWwgYmVmb3JlIHJlLXJ1bm5pbmc6DQpgYGB7cn0NCiMgbmV3IG1vZGVsIG9iamVjdCB3aXRoIHRlcm1zIHJlbW92ZWQNCndyaXRlKCINCiAgDQogIG1vZGVsew0KICAgIA0KICAgICMgcHJpb3JzDQogICAgICANCiAgICAgIGludGVyY2VwdCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIA0KICAgICAgYi5jb21wZXQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnNocnViX2NvdiB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuZ3JhbWluX2NvdiB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc3JpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50cmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRjd3MgfiBkbm9ybSgwLCAwLjAwMDEpDQoNCiAgICAgIHNpZ21hLnBsb3Rncm91cCB+IGR1bmlmKDAsMTAwKQ0KICAgICAgdGF1LnBsb3Rncm91cCA8LSAxLyhzaWdtYS5wbG90Z3JvdXAgKiBzaWdtYS5wbG90Z3JvdXApDQogICAgICANCiAgICAgIGIudGVtcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcGNvbnQueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgYi50ZW1wWHRjd3MgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wWHRjd3MyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIHBoaSB+IGRnYW1tYSgwLjEsIDAuMSkNCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBkaXNjcmV0ZSBwYXJ0DQoNCiAgICAgIGZvciAoaSBpbiAxOk5fZGlzY3JldGUpeyANCiAgICAgICAgY292LmRpc1tpXSB+IGRiZXJuKG11W2ldKQ0KICAgICAgICBsb2dpdChtdVtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmRpc1tpXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5jb21wZXQgKiBjb21wZXQuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNocnViX2NvdiAqIHNocnViX2Nvdi5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuZ3JhbWluX2NvdiAqIGdyYW1pbl9jb3YuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEuZGlzW2ldICogdGN3cy5kaXNbaV0gKyAgICAgICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBYdGN3czIgKiAodGVtcGpqYS5kaXNbaV1eMikgKiB0Y3dzLmRpc1tpXSArICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgYi50Y3dzICogdGN3cy5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLmRpc1tpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5kaXNbaV0NCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBjb250aW51b3VzIHBhcnQNCg0KICAgICAgZm9yIChqIGluIDE6Tl9jb250KXsNCiAgICAgICAgY292LmNvbnRbal0gfiBkYmV0YShwW2pdLCBxW2pdKQ0KICAgICAgICBwW2pdIDwtIG11MltqXSAqIHBoaQ0KICAgICAgICBxW2pdIDwtICgxIC0gbXUyW2pdKSAqIHBoaQ0KICAgICAgICBsb2dpdChtdTJbal0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5jb250W2pdXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc2hydWJfY292ICogc2hydWJfY292LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi5ncmFtaW5fY292ICogZ3JhbWluX2Nvdi5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcFh0Y3dzICogdGVtcGpqYS5jb250W2pdICogdGN3cy5jb250W2pdICsgICAgICAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHRlbXBqamEuY29udFtqXV4yKSAqIHRjd3MuY29udFtqXSArICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgYi50Y3dzICogdGN3cy5jb250W2pdICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmNvbnRbal0NCiAgICAgIH0NCg0KDQogICAgICBmb3IgKGsgaW4gMTpOX3Bsb3Rncm91cHMpeyAjIGxlbmd0aCBvZiB0b3RhbCBwbG90Z3JvdXBzDQogICAgICAgIGJfcGxvdGdyb3VwW2tdIH4gZG5vcm0obXUucGxvdGdyb3VwW2tdLHRhdS5wbG90Z3JvdXApDQogICAgICAgIG11LnBsb3Rncm91cFtrXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzLCBsaW5lYXIgYW5kIHF1YWRyYXRpYyB0ZXJtDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogdGVtcGpqYS50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBqamEueDIgKiAodGVtcGpqYS50b3Rba11eMikgKyANCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54ICogdGVtcGNvbnQudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wY29udC54MiAqICh0ZW1wY29udC50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54ICogcHJlY2lwamphLnRvdFtrXSAjICsgDQogICAgICAgICAgICAgICAgICAgICMgYi5wcmVjaXBqamEueDIgKiAocHJlY2lwamphLnRvdFtrXV4yKSANCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgICAjIGFkZCBwcmVkaWN0ZWQgdmFsdWVzIChkZXJpdmVkIHBhcmFtZXRlcnMpDQogICAgICBmb3IgKG0gaW4gMTpOeGhhdCl7DQogICAgICAgIHBoYXRfY29tcGV0W21dIDwtIGludGVyY2VwdCArIGIuY29tcGV0ICogeGhhdF9jb21wZXRbbV0NCiAgICAgICAgcGhhdF9ncmFtaW5vaWRfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5ncmFtaW5fY292ICogeGhhdF9ncmFtaW5vaWRfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zaHJ1Yl9jb3ZlclttXSA8LSBpbnRlcmNlcHQgKyBiLnNocnViX2NvdiAqIHhoYXRfc2hydWJfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zcmlbbV0gPC0gaW50ZXJjZXB0ICsgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnRyaSAqIHhoYXRfdHJpW21dDQogICAgICAgIHBoYXRfdGN3c1ttXSA8LSBpbnRlcmNlcHQgKyBiLnRjd3MgKiB4aGF0X3Rjd3NbbV0NCiAgICAgICAgcGhhdF90ZW1wamphW21dIDwtIGludGVyY2VwdCArIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICMgKyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphW21dXjIpDQogICAgICAgIHBoYXRfdGVtcGNvbnRbbV0gPC0gaW50ZXJjZXB0ICsgYi50ZW1wY29udC54ICogeGhhdF90ZW1wY29udFttXSAjICsgYi50ZW1wY29udC54MiAqICh4aGF0X3RlbXBjb250W21dXjIpDQogICAgICAgIHBoYXRfcHJlY2lwamphW21dIDwtIGludGVyY2VwdCArIGIucHJlY2lwamphLnggKiB4aGF0X3ByZWNpcGpqYVttXSAjICsgYi5wcmVjaXBqamEueDIgKiAoeGhhdF9wcmVjaXBqamFbbV1eMikNCiAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcFhtb2lzdFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphW21dXjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50Y3dzICogeGhhdF90Y3dzMltwXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcFh0Y3dzICogeGhhdF90ZW1wamphW21dICogeGhhdF90Y3dzMltwXSAjICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBYdGN3czIgKiAoeGhhdF90ZW1wamphW21dXjIpICogeGhhdF90Y3dzMltwXQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KDQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuQmV0TmFuMi5qYWdzIikpDQoNCiMgc3BlY2lmeSBuZXcgc2V0IG9mIHBhcmFtZXRlcnMgdG8gYmUgbW9uaXRvcmVkDQpwYXJhbXNfQmV0TmFuMiA8LSBjKCJpbnRlcmNlcHQiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wamphLngiLCAjICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgImIuc2hydWJfY292IiwNCiAgICAgICAgICAgICAgICAgICAgImIuZ3JhbWluX2NvdiIsDQogICAgICAgICAgICAgICAgICAgICJiLnNyaSIsDQogICAgICAgICAgICAgICAgICAgICJiLnRyaSIsDQogICAgICAgICAgICAgICAgICAgICJiLnRjd3MiLA0KICAgICAgICAgICAgICAgICAgICAiYl9wbG90Z3JvdXBbMV0iLCJiX3Bsb3Rncm91cFsyXSIsImJfcGxvdGdyb3VwWzNdIiwiYl9wbG90Z3JvdXBbNjNdIiwNCiAgICAgICAgICAgICAgICAgICAgInNpZ21hLnBsb3Rncm91cCIsDQogICAgICAgICAgICAgICAgICAgICJwaGkiLA0KICAgICAgICAgICAgICAgICAgICAicGhhdF9jb21wZXQiLCAicGhhdF9zaHJ1Yl9jb3ZlciIsICJwaGF0X2dyYW1pbm9pZF9jb3ZlciIsIA0KICAgICAgICAgICAgICAgICAgICAicGhhdF9zcmkiLCAicGhhdF90cmkiLCAicGhhdF90Y3dzIiwgDQogICAgICAgICAgICAgICAgICAgICJwaGF0X3RlbXBqamEiLCAicGhhdF90ZW1wY29udCIsICJwaGF0X3ByZWNpcGpqYSIsDQogICAgICAgICAgICAgICAgICAgICJwaGF0X3RlbXBYbW9pc3QiKQ0KDQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuQmV0TmFuLmRhdGEsICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc19CZXROYW4yLCAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LkJldE5hbjIuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbjIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbjIkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuQmV0TmFuMiA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbjIkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuQmV0TmFuMltwYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbjIkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuQmV0TmFuMltwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbjIgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuQmV0TmFuMiwgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0Kc2F2ZShjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yLCBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgInNwZWNpZXNfdGN3cyIsICJtb2RlbF9vdXRwdXRfQmV0TmFuMi5SZGF0YSIpKQ0KIyBsb2FkKGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X0JldE5hbjIuUmRhdGEiKSkNCg0KIyBlZmZlY3Qgc2l6ZSBwbG90DQooZWZmZWN0X3NpemVfcGxvdC5CZXROYW4yIDwtIG1vZGVsX3Bsb3Rfc2lnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbjIsIHRpdGxlX3N0cmluZyA9ICJCZXR1bGEgbmFuYSIsIHBsb3Rfd2lkdGggPSA5LjUpKQ0KDQpgYGANCg0KKiAqKnBvc2l0aXZlIHJlc3BvbnNlIHRvIHRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5IGFuZCBtb3JlIGNvbnNlcnZhdGl2ZSBjb21tdW5pdGllcywgbmVnYXRpdmUgcmVzcG9uc2UgdG8gZ3JhbWlub2lkIGNvdmVyIChzaWcuKSoqDQoqIHNsaWdodGx5IHBvc2l0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIHRvcG9ncmFwaGljIHdldG5lc3MgKG4ucy4pDQoNCjxicj4NCg0KDQojIyMgKkNhc3Npb3BlIHRldHJhZ29uYSoNCmBgYHtyfQ0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkNhc1RldCA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuQ2FzVGV0LmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5zcGVjLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQ2FzVGV0KSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LkNhc1RldCA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQ2FzVGV0JEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQogICMgbXV0YXRlKHBhcmFtID0gYXMudmVjdG9yKHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhjb2VmZi5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQpLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuQ2FzVGV0IDwtIGRhdGEuZnJhbWUocTUgPSBOQSwgcTk1ID0gTkEsIHBhcmFtID0gTkEpDQpmb3IgKHBhcmFtIGluIDE6KGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQ2FzVGV0JEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLkNhc1RldFtwYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkNhc1RldCRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5DYXNUZXRbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkNhc1RldCRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuQ2FzVGV0ICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLkNhc1RldCwgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KQ0KDQpwcmludChjb2VmZi5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQpDQoNCnNhdmUoY29lZmYuc2hydWJfZ3JhZGllbnQuQ2FzVGV0LCBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgInNwZWNpZXNfdGN3cyIsICJtb2RlbF9vdXRwdXRfQ2FzVGV0LlJkYXRhIikpDQoNCmBgYA0KDQoqICoqbm90IGNvbnZlcmdpbmcqKjogbGFyZ2UgUi1oYXQgdmFsdWVzICh+IDEuMykgKG9ubHkgMTYgbm9uLXplcm8gdmFsdWVzIGFjcm9zcyBwbG90IGdyb3VwcykNCg0KPGJyPg0KDQojIyMgKkVtcGV0cnVtIG5pZ3J1bSoNCmBgYHtyfQ0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZyA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuRW1wTmlnLmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5zcGVjLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuRW1wTmlnKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LkVtcE5pZyA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuRW1wTmlnJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQogICMgbXV0YXRlKHBhcmFtID0gYXMudmVjdG9yKHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhjb2VmZi5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcpLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuRW1wTmlnIDwtIGRhdGEuZnJhbWUocTUgPSBOQSwgcTk1ID0gTkEsIHBhcmFtID0gTkEpDQpmb3IgKHBhcmFtIGluIDE6KGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuRW1wTmlnJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLkVtcE5pZ1twYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZyRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5FbXBOaWdbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZyRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuRW1wTmlnICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLkVtcE5pZywgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0Kc2F2ZShjb2VmZi5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcsIGZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dHMiLCAic3BlY2llc190Y3dzIiwgImZpcnN0X3J1bnNfY29udmVyZ2VkIiwgIm1vZGVsX291dHB1dF9FbXBOaWcuUmRhdGEiKSkNCiMgbG9hZChmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dHMiLCAic3BlY2llc190Y3dzIiwgImZpcnN0X3J1bnNfY29udmVyZ2VkIiwgIm1vZGVsX291dHB1dF9FbXBOaWcuUmRhdGEiKSkNCg0KIyBlZmZlY3Qgc2l6ZSBwbG90DQooZWZmZWN0X3NpemVfcGxvdC5FbXBOaWcgPC0gbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkVtcE5pZywgdGl0bGVfc3RyaW5nID0gIkVtcGV0cnVtIG5pZ3J1bSIsIHBsb3Rfd2lkdGggPSAxMi41KSkNCg0KYGBgDQoNCiogKnBvc2l0aXZlIGxpbmVhciByZWxhdGlvbnNoaXAgdG8gc3VtbWVyIHByZWNpcGl0YXRpb24gYW5kIFRDIHdldG5lc3MgKHNpZy4pKg0KDQo8YnI+DQoNCkFzIG5vbmUgb2YgdGhlIHF1YWRyYXRpYyB0ZXJtcyBmb3IgY2xpbWF0aWMgdmFyaWFibGVzIHdlcmUgc2lnbmlmaWNhbnQsIHRoZXkgd2VyZSByZW1vdmVkIGZyb20gdGhlIG1vZGVsIGJlZm9yZSByZS1ydW5uaW5nOg0KYGBge3J9DQojIG5ldyBtb2RlbCBvYmplY3Qgd2l0aCB0ZXJtcyByZW1vdmVkDQp3cml0ZSgiDQogIA0KICBtb2RlbHsNCiAgICANCiAgICAjIHByaW9ycw0KICAgICAgDQogICAgICBpbnRlcmNlcHQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICANCiAgICAgIGIuY29tcGV0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zaHJ1Yl9jb3YgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLmdyYW1pbl9jb3YgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnNyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudHJpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50Y3dzIH4gZG5vcm0oMCwgMC4wMDAxKQ0KDQogICAgICBzaWdtYS5wbG90Z3JvdXAgfiBkdW5pZigwLDEwMCkNCiAgICAgIHRhdS5wbG90Z3JvdXAgPC0gMS8oc2lnbWEucGxvdGdyb3VwICogc2lnbWEucGxvdGdyb3VwKQ0KICAgICAgDQogICAgICBiLnRlbXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBjb250LngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnByZWNpcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIucHJlY2lwamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIGIudGVtcFh0Y3dzIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcFh0Y3dzMiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICBwaGkgfiBkZ2FtbWEoMC4xLCAwLjEpDQogICAgICANCiAgICAgIA0KICAgICMgTElLRUxJSE9PRCBmb3IgZGlzY3JldGUgcGFydA0KDQogICAgICBmb3IgKGkgaW4gMTpOX2Rpc2NyZXRlKXsgDQogICAgICAgIGNvdi5kaXNbaV0gfiBkYmVybihtdVtpXSkNCiAgICAgICAgbG9naXQobXVbaV0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5kaXNbaV1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zaHJ1Yl9jb3YgKiBzaHJ1Yl9jb3YuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLmdyYW1pbl9jb3YgKiBncmFtaW5fY292LmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MgKiB0ZW1wamphLmRpc1tpXSAqIHRjd3MuZGlzW2ldICsgICAgICAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHRlbXBqamEuZGlzW2ldXjIpICogdGN3cy5kaXNbaV0gKyAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS5kaXNbaV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkuZGlzW2ldDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICMgTElLRUxJSE9PRCBmb3IgY29udGludW91cyBwYXJ0DQoNCiAgICAgIGZvciAoaiBpbiAxOk5fY29udCl7DQogICAgICAgIGNvdi5jb250W2pdIH4gZGJldGEocFtqXSwgcVtqXSkNCiAgICAgICAgcFtqXSA8LSBtdTJbal0gKiBwaGkNCiAgICAgICAgcVtqXSA8LSAoMSAtIG11MltqXSkgKiBwaGkNCiAgICAgICAgbG9naXQobXUyW2pdKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuY29udFtqXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5jb21wZXQgKiBjb21wZXQuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNocnViX2NvdiAqIHNocnViX2Nvdi5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIuZ3JhbWluX2NvdiAqIGdyYW1pbl9jb3YuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEuY29udFtqXSAqIHRjd3MuY29udFtqXSArICAgICAgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcFh0Y3dzMiAqICh0ZW1wamphLmNvbnRbal1eMikgKiB0Y3dzLmNvbnRbal0gKyAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHRlbXBqamEudG90W2tdXjIpICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHRlbXBjb250LnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAodGVtcGNvbnQudG90W2tdXjIpICsNCiAgICAgICAgICAgICAgICAgICAgYi5wcmVjaXBqamEueCAqIHByZWNpcGpqYS50b3Rba10gIyArIA0KICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHByZWNpcGpqYS50b3Rba11eMikgDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgIyBhZGQgcHJlZGljdGVkIHZhbHVlcyAoZGVyaXZlZCBwYXJhbWV0ZXJzKQ0KICAgICAgZm9yIChtIGluIDE6TnhoYXQpew0KICAgICAgICBwaGF0X2NvbXBldFttXSA8LSBpbnRlcmNlcHQgKyBiLmNvbXBldCAqIHhoYXRfY29tcGV0W21dDQogICAgICAgIHBoYXRfZ3JhbWlub2lkX2NvdmVyW21dIDwtIGludGVyY2VwdCArIGIuZ3JhbWluX2NvdiAqIHhoYXRfZ3JhbWlub2lkX2NvdmVyW21dDQogICAgICAgIHBoYXRfc2hydWJfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5zaHJ1Yl9jb3YgKiB4aGF0X3NocnViX2NvdmVyW21dDQogICAgICAgIHBoYXRfc3JpW21dIDwtIGludGVyY2VwdCArIGIuc3JpICogeGhhdF9zcmlbbV0NCiAgICAgICAgcGhhdF90cmlbbV0gPC0gaW50ZXJjZXB0ICsgYi50cmkgKiB4aGF0X3RyaVttXQ0KICAgICAgICBwaGF0X3Rjd3NbbV0gPC0gaW50ZXJjZXB0ICsgYi50Y3dzICogeGhhdF90Y3dzW21dDQogICAgICAgIHBoYXRfdGVtcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSAjICsgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKQ0KICAgICAgICBwaGF0X3RlbXBjb250W21dIDwtIGludGVyY2VwdCArIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gIyArIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnByZWNpcGpqYS54ICogeGhhdF9wcmVjaXBqamFbbV0gIyArIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICANCiAgICAgICAgZm9yIChwIGluIDE6TnhoYXQyKXsNCiAgICAgICAgICBwaGF0X3RlbXBYbW9pc3RbbSxwXSA8LSBpbnRlcmNlcHQgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHhoYXRfdGVtcGpqYVttXSAqIHhoYXRfdGN3czJbcF0gIyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHhoYXRfdGVtcGpqYVttXV4yKSAqIHhoYXRfdGN3czJbcF0NCiAgICAgICAgICB9DQogICAgICAgIH0NCg0KICAgIA0KICAgICAgfQ0KICAiLCBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LkVtcE5pZzIuamFncyIpKQ0KDQojIHNwZWNpZnkgbmV3IHNldCBvZiBwYXJhbWV0ZXJzIHRvIGJlIG1vbml0b3JlZA0KcGFyYW1zX0VtcE5pZzIgPC0gYygiaW50ZXJjZXB0IiwNCiAgICAgICAgICAgICAgICAgICAgImIudGVtcGpqYS54IiwgIyAiYi50ZW1wamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAgImIudGVtcGNvbnQueCIsICMgImIudGVtcGNvbnQueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5wcmVjaXBqamEueCIsICMgImIucHJlY2lwamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAgImIuY29tcGV0IiwgDQogICAgICAgICAgICAgICAgICAgICJiLnNocnViX2NvdiIsDQogICAgICAgICAgICAgICAgICAgICJiLmdyYW1pbl9jb3YiLA0KICAgICAgICAgICAgICAgICAgICAiYi5zcmkiLA0KICAgICAgICAgICAgICAgICAgICAiYi50cmkiLA0KICAgICAgICAgICAgICAgICAgICAiYi50Y3dzIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc2hydWJfY292ZXIiLCAicGhhdF9ncmFtaW5vaWRfY292ZXIiLCANCiAgICAgICAgICAgICAgICAgICAgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdGN3cyIsIA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wamphIiwgInBoYXRfdGVtcGNvbnQiLCAicGhhdF9wcmVjaXBqamEiLA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wWG1vaXN0IikNCg0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZzIgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLkVtcE5pZy5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX0VtcE5pZzIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5FbXBOaWcyLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuRW1wTmlnMikgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLkVtcE5pZzIgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLkVtcE5pZzJbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLkVtcE5pZzJbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZzIkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuRW1wTmlnMiA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLkVtcE5pZzIsIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCnNhdmUoY29lZmYuc2hydWJfZ3JhZGllbnQuRW1wTmlnMiwgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X0VtcE5pZzIuUmRhdGEiKSkNCiMgbG9hZChmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dHMiLCAic3BlY2llc190Y3dzIiwgIm1vZGVsX291dHB1dF9FbXBOaWcyLlJkYXRhIikpDQoNCiMgZWZmZWN0IHNpemUgcGxvdA0KKGVmZmVjdF9zaXplX3Bsb3QuRW1wTmlnMiA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyLCB0aXRsZV9zdHJpbmcgPSAiRW1wZXRydW0gbmlncnVtIiwgcGxvdF93aWR0aCA9IDkuNSkpDQoNCmBgYA0KDQoqICoqbmVnYXRpdmUgcmVzcG9uc2UgdG8gdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHksIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIHByZWNpcGl0YXRpb24gKGxpbmVhcikgYW5kIFRDd2V0bmVzcyAoc2lnLikqKg0KKiBzbGlnaHRseSBuZWdhdGl2ZSByZXNwb25zZSB0byBncmFtaW5vaWQgY292ZXIgKG4ucy4pDQoNCjxicj4NCg0KIyMjICpQaHlsbG9kb2NlIGNhZXJ1bGVhKg0KYGBge3J9DQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUGh5Q2FlIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5QaHlDYWUuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuUGh5Q2FlIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlBoeUNhZSksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5QaHlDYWUgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuUGh5Q2FlW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUGh5Q2FlJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlBoeUNhZVtwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUGh5Q2FlJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlBoeUNhZSA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuUGh5Q2FlLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQpzYXZlKGNvZWZmLnNocnViX2dyYWRpZW50LlBoeUNhZSwgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X1BoeUNhZS5SZGF0YSIpKQ0KDQpgYGANCg0KKiAqKm5vdCBjb252ZXJnZWQgd2VsbCoqIHJlbGF0aXZlbHkgbGFyZ2UgUi1oYXQgdmFsdWVzICh+IDEuMDIpIChvbmx5IDEwIG5vbi16ZXJvIHZhbHVlcyBhY3Jvc3MgcGxvdCBncm91cHMpDQoNCjxicj4NCg0KIyMjICpSaG9kb2RlbmRyb24gZ3JvZW5sYW5kaWN1bSoNCmBgYHtyfQ0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybyA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuUmhvR3JvLmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5zcGVjLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LlJob0dybyA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQogICMgbXV0YXRlKHBhcmFtID0gYXMudmVjdG9yKHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8pLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuUmhvR3JvIDwtIGRhdGEuZnJhbWUocTUgPSBOQSwgcTk1ID0gTkEsIHBhcmFtID0gTkEpDQpmb3IgKHBhcmFtIGluIDE6KGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLlJob0dyb1twYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybyRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5SaG9Hcm9bcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybyRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8gPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvR3JvICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLlJob0dybywgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0Kc2F2ZShjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8sIGZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dHMiLCAic3BlY2llc190Y3dzIiwgImZpcnN0X3J1bnNfY29udmVyZ2VkIiwgIm1vZGVsX291dHB1dF9SaG9Hcm8uUmRhdGEiKSkNCiMgbG9hZChmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dHMiLCAic3BlY2llc190Y3dzIiwgImZpcnN0X3J1bnNfY29udmVyZ2VkIiwgIm1vZGVsX291dHB1dF9SaG9Hcm8uUmRhdGEiKSkNCg0KIyBlZmZlY3Qgc2l6ZSBwbG90DQooZWZmZWN0X3NpemVfcGxvdC5SaG9Hcm8gPC0gbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LlJob0dybywgdGl0bGVfc3RyaW5nID0gIlJob2RvZGVuZHJvbiBncm9lbmxhbmRpY3VtIiwgcGxvdF93aWR0aCA9IDEyLjUpKQ0KDQpgYGANCg0KKiAqKm5lZ2F0aXZlIHJlc3BvbnNlIHRvIGdyYW1pbm9pZCBjb3ZlciAobS5zLikqKiANCiogc2xpZ2h0bHkgcG9zaXRpdmUgcmVzcG9uc2UgdG8gdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHksIHNvbGFyIHJhZGlhdGlvbiwgdGVycmFpbiBoZXRlcm9nZW5laXR5LCBUQyB3ZXRuZXNzOyBzbGlnaHRseSB1bmltb2RhbCByZXNwb25zZSB0byBzdW1tZXIgdGVtcGVyYXR1cmUgKG4ucy4pDQoNCjxicj4NCg0KQXMgdGhlIHF1YWRyYXRpYyB0ZXJtcyBmb3IgY2xpbWF0aWMgdmFyaWFibGVzIHdlcmUgbm90IHNpZ25pZmljYW50LCB0aGV5IHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBtb2RlbCBiZWZvcmUgcmUtcnVubmluZzoNCmBgYHtyfQ0KIyBuZXcgbW9kZWwgb2JqZWN0IHdpdGggdGVybXMgcmVtb3ZlZA0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQogICAgDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmNvbXBldCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc2hydWJfY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5ncmFtaW5fY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zcmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudGN3cyB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBjb250LnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wY29udC54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi5wcmVjaXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnByZWNpcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICBiLnRlbXBYdGN3cyB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wWHRjd3MyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIHBoaSB+IGRnYW1tYSgwLjEsIDAuMSkNCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBkaXNjcmV0ZSBwYXJ0DQoNCiAgICAgIGZvciAoaSBpbiAxOk5fZGlzY3JldGUpeyANCiAgICAgICAgY292LmRpc1tpXSB+IGRiZXJuKG11W2ldKQ0KICAgICAgICBsb2dpdChtdVtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmRpc1tpXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5jb21wZXQgKiBjb21wZXQuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNocnViX2NvdiAqIHNocnViX2Nvdi5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuZ3JhbWluX2NvdiAqIGdyYW1pbl9jb3YuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEuZGlzW2ldICogdGN3cy5kaXNbaV0gKyAgICAgICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBYdGN3czIgKiAodGVtcGpqYS5kaXNbaV1eMikgKiB0Y3dzLmRpc1tpXSArICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgYi50Y3dzICogdGN3cy5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLmRpc1tpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5kaXNbaV0NCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBjb250aW51b3VzIHBhcnQNCg0KICAgICAgZm9yIChqIGluIDE6Tl9jb250KXsNCiAgICAgICAgY292LmNvbnRbal0gfiBkYmV0YShwW2pdLCBxW2pdKQ0KICAgICAgICBwW2pdIDwtIG11MltqXSAqIHBoaQ0KICAgICAgICBxW2pdIDwtICgxIC0gbXUyW2pdKSAqIHBoaQ0KICAgICAgICBsb2dpdChtdTJbal0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5jb250W2pdXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc2hydWJfY292ICogc2hydWJfY292LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi5ncmFtaW5fY292ICogZ3JhbWluX2Nvdi5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcFh0Y3dzICogdGVtcGpqYS5jb250W2pdICogdGN3cy5jb250W2pdICsgICAgICAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHRlbXBqamEuY29udFtqXV4yKSAqIHRjd3MuY29udFtqXSArICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgYi50Y3dzICogdGN3cy5jb250W2pdICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmNvbnRbal0NCiAgICAgIH0NCg0KDQogICAgICBmb3IgKGsgaW4gMTpOX3Bsb3Rncm91cHMpeyAjIGxlbmd0aCBvZiB0b3RhbCBwbG90Z3JvdXBzDQogICAgICAgIGJfcGxvdGdyb3VwW2tdIH4gZG5vcm0obXUucGxvdGdyb3VwW2tdLHRhdS5wbG90Z3JvdXApDQogICAgICAgIG11LnBsb3Rncm91cFtrXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzLCBsaW5lYXIgYW5kIHF1YWRyYXRpYyB0ZXJtDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogdGVtcGpqYS50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBqamEueDIgKiAodGVtcGpqYS50b3Rba11eMikgKyANCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54ICogdGVtcGNvbnQudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wY29udC54MiAqICh0ZW1wY29udC50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54ICogcHJlY2lwamphLnRvdFtrXSAjICsgDQogICAgICAgICAgICAgICAgICAgICMgYi5wcmVjaXBqamEueDIgKiAocHJlY2lwamphLnRvdFtrXV4yKSANCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgICAjIGFkZCBwcmVkaWN0ZWQgdmFsdWVzIChkZXJpdmVkIHBhcmFtZXRlcnMpDQogICAgICBmb3IgKG0gaW4gMTpOeGhhdCl7DQogICAgICAgIHBoYXRfY29tcGV0W21dIDwtIGludGVyY2VwdCArIGIuY29tcGV0ICogeGhhdF9jb21wZXRbbV0NCiAgICAgICAgcGhhdF9ncmFtaW5vaWRfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5ncmFtaW5fY292ICogeGhhdF9ncmFtaW5vaWRfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zaHJ1Yl9jb3ZlclttXSA8LSBpbnRlcmNlcHQgKyBiLnNocnViX2NvdiAqIHhoYXRfc2hydWJfY292ZXJbbV0NCiAgICAgICAgcGhhdF9zcmlbbV0gPC0gaW50ZXJjZXB0ICsgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnRyaSAqIHhoYXRfdHJpW21dDQogICAgICAgIHBoYXRfdGN3c1ttXSA8LSBpbnRlcmNlcHQgKyBiLnRjd3MgKiB4aGF0X3Rjd3NbbV0NCiAgICAgICAgcGhhdF90ZW1wamphW21dIDwtIGludGVyY2VwdCArIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICMgKyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphW21dXjIpDQogICAgICAgIHBoYXRfdGVtcGNvbnRbbV0gPC0gaW50ZXJjZXB0ICsgYi50ZW1wY29udC54ICogeGhhdF90ZW1wY29udFttXSAjICsgYi50ZW1wY29udC54MiAqICh4aGF0X3RlbXBjb250W21dXjIpDQogICAgICAgIHBoYXRfcHJlY2lwamphW21dIDwtIGludGVyY2VwdCArIGIucHJlY2lwamphLnggKiB4aGF0X3ByZWNpcGpqYVttXSAjICsgYi5wcmVjaXBqamEueDIgKiAoeGhhdF9wcmVjaXBqamFbbV1eMikNCiAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcFhtb2lzdFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphW21dXjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50Y3dzICogeGhhdF90Y3dzMltwXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcFh0Y3dzICogeGhhdF90ZW1wamphW21dICogeGhhdF90Y3dzMltwXSAjICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBYdGN3czIgKiAoeGhhdF90ZW1wamphW21dXjIpICogeGhhdF90Y3dzMltwXQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KDQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuUmhvR3JvMi5qYWdzIikpDQoNCiMgc3BlY2lmeSBuZXcgc2V0IG9mIHBhcmFtZXRlcnMgdG8gYmUgbW9uaXRvcmVkDQpwYXJhbXNfUmhvR3JvMiA8LSBjKCJpbnRlcmNlcHQiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wamphLngiLCAjICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgImIuc2hydWJfY292IiwNCiAgICAgICAgICAgICAgICAgICAgImIuZ3JhbWluX2NvdiIsDQogICAgICAgICAgICAgICAgICAgICJiLnNyaSIsDQogICAgICAgICAgICAgICAgICAgICJiLnRyaSIsDQogICAgICAgICAgICAgICAgICAgICJiLnRjd3MiLA0KICAgICAgICAgICAgICAgICAgICAiYl9wbG90Z3JvdXBbMV0iLCJiX3Bsb3Rncm91cFsyXSIsImJfcGxvdGdyb3VwWzNdIiwiYl9wbG90Z3JvdXBbNjNdIiwNCiAgICAgICAgICAgICAgICAgICAgInNpZ21hLnBsb3Rncm91cCIsDQogICAgICAgICAgICAgICAgICAgICJwaGkiLA0KICAgICAgICAgICAgICAgICAgICAicGhhdF9jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgInBoYXRfc2hydWJfY292ZXIiLCAicGhhdF9ncmFtaW5vaWRfY292ZXIiLCANCiAgICAgICAgICAgICAgICAgICAgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdGN3cyIsIA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wamphIiwgInBoYXRfdGVtcGNvbnQiLCAicGhhdF9wcmVjaXBqamEiLA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wWG1vaXN0IikNCg0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybzIgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLlJob0dyby5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX1Job0dybzIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvMikgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQogICMgbXV0YXRlKHBhcmFtID0gYXMudmVjdG9yKHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8pLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuUmhvR3JvMiA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybzIkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuUmhvR3JvMltwYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybzIkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuUmhvR3JvMltwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvMiRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LlJob0dybzIgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuUmhvR3JvMiwgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0Kc2F2ZShjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yLCBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgInNwZWNpZXNfdGN3cyIsICJtb2RlbF9vdXRwdXRfUmhvR3JvMi5SZGF0YSIpKQ0KIyBsb2FkKGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X1Job0dybzIuUmRhdGEiKSkNCg0KIyBlZmZlY3Qgc2l6ZSBwbG90DQooZWZmZWN0X3NpemVfcGxvdC5SaG9Hcm8yIDwtIG1vZGVsX3Bsb3RfbWFyZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yLCB0aXRsZV9zdHJpbmcgPSAiUmhvZG9kZW5kcm9uIGdyb2VubGFuZGljdW0iLCBwbG90X3dpZHRoID0gOS41KSkNCg0KYGBgDQoNCiogKipwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBUQ3dldG5lc3MgKHNpZy4pKiosICpwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCB0ZW1wZXJhdHVyZSB2YXJpYWJpbGl0eSwgbmVnYXRpdmUgd2l0aCBncmFtaW5vaWQgY292ZXIgKG0ucy4pKg0KKiBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBwcmVjaXBpdGF0aW9uIChsaW5lYXIpIChuLnMuKQ0KDQo8YnI+DQoNCiMjIyAqUmhvZG9kZW5kcm9uIHRvbWVudG9zdW0qDQpgYGB7cn0NCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Ub20gPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLlJob1RvbS5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzX3Rjd3MiLCAic2hydWJfZ3JhZGllbnQuc3BlYy5qYWdzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY2hhaW5zID0gMywgICAgICAgICAgICAgICAgICAgICAgICMgbm8uIE1hcmtvdiBjaGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLml0ZXIgPSAxMDAwMDAsIG4uYnVybmluID0gNzAwMDAsICAjIG5vLiBpdGVyYXRpb25zICYgYnVybi1pbiBmcmFjdGlvbiBwZXIgY2hhaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnRoaW4gPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaW5uaW5nIHJhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESUMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAjIGRvIG5vdCBjb21wdXRlIGRldmlhbmNlLCBwRCwgYW5kIERJQw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcuZGlyZWN0b3J5ID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MuYmFyID0gInRleHQiKQ0KDQojIHBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob1RvbSkgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Ub20gPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob1RvbSRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvVG9tKSwiW1tdIixmaXhlZD1GQUxTRSksICJbIiwgMSkpKSAjJT4lIHByaW50DQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLlJob1RvbSA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob1RvbSRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5SaG9Ub21bcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Ub20kQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuUmhvVG9tW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Ub20kQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvVG9tIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LlJob1RvbSAlPiUgDQogIGxlZnRfam9pbihjaV85MC5SaG9Ub20sIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCnNhdmUoY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvVG9tLCBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgInNwZWNpZXNfdGN3cyIsICJtb2RlbF9vdXRwdXRfUmhvVG9tLlJkYXRhIikpDQoNCmBgYA0KDQoqICoqbm90IGNvbnZlcmdpbmcqKjogcmVhbGx5IGxhcmdlIFItaGF0IHZhbHVlcyAofiAyLjcpLCBsYXJnZSB2YXJpYXRpb24gaW4gcGFyYW1ldGVyIGVzdGltYXRlcyAob25seSAxMyBub24temVybyB2YWx1ZXMpDQoNCjxicj4NCg0KIyMjICpTYWxpeCBhcmN0b3BoaWxhKg0KYGBge3J9DQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsQXJjIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5TYWxBcmMuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxBcmMpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsQXJjIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxBcmMkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEFyYyksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5TYWxBcmMgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxBcmMkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuU2FsQXJjW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsQXJjJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlNhbEFyY1twYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsQXJjJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlNhbEFyYyA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxBcmMgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuU2FsQXJjLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQojIFItaGF0cyBsb29rIG9rYXkgPT4gY2hlY2sgdHJhY2VwbG90cw0KIyB0cmFjZXBsb3QoY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsQXJjKQ0KDQpzYXZlKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEFyYywgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X1NhbEFyYy5SZGF0YSIpKQ0KDQpgYGANCg0KKiAqKm5vdCBjb252ZXJnaW5nIHdlbGwqKjogcmVsYXRpdmVseSBsYXJnZSBSLWhhdCB2YWx1ZXMgKDwgMS4wNCksIGFuZCBxdWl0ZSBzb21lIHZhcmlhdGlvbiBpbiB0cmFjZSBwbG90cywgZXNwZWNpYWxseSBmb3IgY2xpbWF0aWMgcGFyYW1ldGVycyAob25seSAxMyBub24temVybyB2YWx1ZXMgYWNyb3NzIHBsb3QgZ3JvdXBzKQ0KDQo8YnI+DQoNCiMjIyAqU2FsaXggZ2xhdWNhKg0KYGBge3J9DQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5TYWxHbGEuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYSksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5TYWxHbGEgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuU2FsR2xhW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlNhbEdsYVtwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYSA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuU2FsR2xhLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQpzYXZlKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYSwgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAiZmlyc3RfcnVuc19jb252ZXJnZWQiLCAibW9kZWxfb3V0cHV0X1NhbEdsYS5SZGF0YSIpKQ0KIyBsb2FkKGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAiZmlyc3RfcnVuc19jb252ZXJnZWQiLCAibW9kZWxfb3V0cHV0X1NhbEdsYS5SZGF0YSIpKQ0KDQojIGVmZmVjdCBzaXplIHBsb3QNCihlZmZlY3Rfc2l6ZV9wbG90LlNhbEdsYSA8LSBtb2RlbF9wbG90X21hcmdfZnVuY3Rpb24oY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhLCB0aXRsZV9zdHJpbmcgPSAiU2FsaXggZ2xhdWNhIiwgcGxvdF93aWR0aCA9IDEyLjUpKQ0KDQpgYGANCg0KKiAqKnBvc2l0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIGxlc3MgYWNxdWlzaXRpdmUgY29tbXVuaXRpZXMgKHNpZy4pLCBvdGhlciBzaHJ1YiBjb3ZlciBhbmQgdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgKG0ucy4pKioNCiogc2xpZ2h0bHkgbmVnYXRpdmUgcmVzcG9uc2UgdG8gc3VtbWVyIHRlbXBlcmF0dXJlIChuLnMuKQ0KDQo8YnI+DQoNCkFzIHRoZSBxdWFkcmF0aWMgdGVybXMgZm9yIHN1bW1lciB0ZW1wZXJhdHVyZSwgdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgYW5kIHN1bW1lciBwcmVjaXBpdGF0aW9uIHdlcmUgbm90IHNpZ25pZmljYW50LCB0aGV5IHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBtb2RlbCBiZWZvcmUgcmUtcnVubmluZzoNCmBgYHtyfQ0KIyBuZXcgbW9kZWwgb2JqZWN0IHdpdGggdGVybXMgcmVtb3ZlZA0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQoNCiAgICAjIHByaW9ycw0KICAgICAgDQogICAgICBpbnRlcmNlcHQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICANCiAgICAgIGIuY29tcGV0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zaHJ1Yl9jb3YgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLmdyYW1pbl9jb3YgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnNyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudHJpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50Y3dzIH4gZG5vcm0oMCwgMC4wMDAxKQ0KDQogICAgICBzaWdtYS5wbG90Z3JvdXAgfiBkdW5pZigwLDEwMCkNCiAgICAgIHRhdS5wbG90Z3JvdXAgPC0gMS8oc2lnbWEucGxvdGdyb3VwICogc2lnbWEucGxvdGdyb3VwKQ0KICAgICAgDQogICAgICBiLnRlbXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBjb250LngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnByZWNpcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIucHJlY2lwamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIGIudGVtcFh0Y3dzIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcFh0Y3dzMiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICBwaGkgfiBkZ2FtbWEoMC4xLCAwLjEpDQogICAgICANCiAgICAgIA0KICAgICMgTElLRUxJSE9PRCBmb3IgZGlzY3JldGUgcGFydA0KDQogICAgICBmb3IgKGkgaW4gMTpOX2Rpc2NyZXRlKXsgDQogICAgICAgIGNvdi5kaXNbaV0gfiBkYmVybihtdVtpXSkNCiAgICAgICAgbG9naXQobXVbaV0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5kaXNbaV1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zaHJ1Yl9jb3YgKiBzaHJ1Yl9jb3YuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLmdyYW1pbl9jb3YgKiBncmFtaW5fY292LmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MgKiB0ZW1wamphLmRpc1tpXSAqIHRjd3MuZGlzW2ldICsgICAgICAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHRlbXBqamEuZGlzW2ldXjIpICogdGN3cy5kaXNbaV0gKyAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHNyaS5kaXNbaV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkuZGlzW2ldDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICMgTElLRUxJSE9PRCBmb3IgY29udGludW91cyBwYXJ0DQoNCiAgICAgIGZvciAoaiBpbiAxOk5fY29udCl7DQogICAgICAgIGNvdi5jb250W2pdIH4gZGJldGEocFtqXSwgcVtqXSkNCiAgICAgICAgcFtqXSA8LSBtdTJbal0gKiBwaGkNCiAgICAgICAgcVtqXSA8LSAoMSAtIG11MltqXSkgKiBwaGkNCiAgICAgICAgbG9naXQobXUyW2pdKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuY29udFtqXV0gKyAjIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5jb21wZXQgKiBjb21wZXQuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNocnViX2NvdiAqIHNocnViX2Nvdi5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIuZ3JhbWluX2NvdiAqIGdyYW1pbl9jb3YuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHRlbXBqamEuY29udFtqXSAqIHRjd3MuY29udFtqXSArICAgICAgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcFh0Y3dzMiAqICh0ZW1wamphLmNvbnRbal1eMikgKiB0Y3dzLmNvbnRbal0gKyAgIyBmb3IgaW50ZXJhY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHRjd3MuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHRlbXBqamEudG90W2tdXjIpICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHRlbXBjb250LnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAodGVtcGNvbnQudG90W2tdXjIpICsNCiAgICAgICAgICAgICAgICAgICAgYi5wcmVjaXBqamEueCAqIHByZWNpcGpqYS50b3Rba10gIyArIA0KICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHByZWNpcGpqYS50b3Rba11eMikgDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgIyBhZGQgcHJlZGljdGVkIHZhbHVlcyAoZGVyaXZlZCBwYXJhbWV0ZXJzKQ0KICAgICAgZm9yIChtIGluIDE6TnhoYXQpew0KICAgICAgICBwaGF0X2NvbXBldFttXSA8LSBpbnRlcmNlcHQgKyBiLmNvbXBldCAqIHhoYXRfY29tcGV0W21dDQogICAgICAgIHBoYXRfZ3JhbWlub2lkX2NvdmVyW21dIDwtIGludGVyY2VwdCArIGIuZ3JhbWluX2NvdiAqIHhoYXRfZ3JhbWlub2lkX2NvdmVyW21dDQogICAgICAgIHBoYXRfc2hydWJfY292ZXJbbV0gPC0gaW50ZXJjZXB0ICsgYi5zaHJ1Yl9jb3YgKiB4aGF0X3NocnViX2NvdmVyW21dDQogICAgICAgIHBoYXRfc3JpW21dIDwtIGludGVyY2VwdCArIGIuc3JpICogeGhhdF9zcmlbbV0NCiAgICAgICAgcGhhdF90cmlbbV0gPC0gaW50ZXJjZXB0ICsgYi50cmkgKiB4aGF0X3RyaVttXQ0KICAgICAgICBwaGF0X3Rjd3NbbV0gPC0gaW50ZXJjZXB0ICsgYi50Y3dzICogeGhhdF90Y3dzW21dDQogICAgICAgIHBoYXRfdGVtcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSAjICsgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKQ0KICAgICAgICBwaGF0X3RlbXBjb250W21dIDwtIGludGVyY2VwdCArIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gIyArIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnByZWNpcGpqYS54ICogeGhhdF9wcmVjaXBqamFbbV0gIyArIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICANCiAgICAgICAgZm9yIChwIGluIDE6TnhoYXQyKXsNCiAgICAgICAgICBwaGF0X3RlbXBYbW9pc3RbbSxwXSA8LSBpbnRlcmNlcHQgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYVttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGN3cyAqIHhoYXRfdGN3czJbcF0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBYdGN3cyAqIHhoYXRfdGVtcGpqYVttXSAqIHhoYXRfdGN3czJbcF0gIyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wWHRjd3MyICogKHhoYXRfdGVtcGpqYVttXV4yKSAqIHhoYXRfdGN3czJbcF0NCiAgICAgICAgICB9DQogICAgICAgIH0NCg0KICAgIA0KICAgICAgfQ0KICAiLCBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LlNhbEdsYTIuamFncyIpKQ0KDQojIHNwZWNpZnkgbmV3IHNldCBvZiBwYXJhbWV0ZXJzIHRvIGJlIG1vbml0b3JlZA0KcGFyYW1zX1NhbEdsYTIgPC0gYygiaW50ZXJjZXB0IiwNCiAgICAgICAgICAgICAgICAgICAgImIudGVtcGpqYS54IiwgIyAiYi50ZW1wamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAgImIudGVtcGNvbnQueCIsICMgImIudGVtcGNvbnQueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5wcmVjaXBqamEueCIsICMgImIucHJlY2lwamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAgImIuY29tcGV0IiwgDQogICAgICAgICAgICAgICAgICAgICJiLnNocnViX2NvdiIsDQogICAgICAgICAgICAgICAgICAgICJiLmdyYW1pbl9jb3YiLA0KICAgICAgICAgICAgICAgICAgICAiYi5zcmkiLA0KICAgICAgICAgICAgICAgICAgICAiYi50cmkiLA0KICAgICAgICAgICAgICAgICAgICAiYi50Y3dzIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc2hydWJfY292ZXIiLCAicGhhdF9ncmFtaW5vaWRfY292ZXIiLCANCiAgICAgICAgICAgICAgICAgICAgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdGN3cyIsIA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wamphIiwgInBoYXRfdGVtcGNvbnQiLCAicGhhdF9wcmVjaXBqamEiLA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wWG1vaXN0IikNCg0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLlNhbEdsYS5kYXRhLCAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXNfU2FsR2xhMiwgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMikgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLlNhbEdsYTIgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuU2FsR2xhMltwYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuU2FsR2xhMltwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMiRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuU2FsR2xhMiwgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0Kc2F2ZShjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLCBmaWxlID0gZmlsZS5wYXRoKCIuLiIsICJkYXRhIiwgInByb2Nlc3NlZCIsICJtb2RlbF9vdXRwdXRzIiwgInNwZWNpZXNfdGN3cyIsICJtb2RlbF9vdXRwdXRfU2FsR2xhMi5SZGF0YSIpKQ0KIyBsb2FkKGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X1NhbEdsYTIuUmRhdGEiKSkNCg0KIyBlZmZlY3Qgc2l6ZSBwbG90DQooZWZmZWN0X3NpemVfcGxvdC5TYWxHbGEyIDwtIG1vZGVsX3Bsb3Rfc2lnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIsIHRpdGxlX3N0cmluZyA9ICJTYWxpeCBnbGF1Y2EiLCBwbG90X3dpZHRoID0gOS41KSkNCg0KYGBgDQoNCiogKipwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBjb25zZXJ2YXRpdmUgY29tbXVuaXRpZXMsIHRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5IChsaW5lYXIpIChzaWcuKSoqDQoqIHNsaWdodGx5IHBvc2l0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIG90aGVyIHNocnViIGNvdmVyIGFuZCBUQ3dldG5lc3MgKG4ucy4pDQoNCjxicj4NCg0KDQojIyMgKlZhY2Npbml1bSB1bGlnaW5vc3VtKg0KYGBge3J9DQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuVmFjVWxpIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5WYWNVbGkuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVsc190Y3dzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuVmFjVWxpIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlZhY1VsaSksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5WYWNVbGkgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuVmFjVWxpW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuVmFjVWxpJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlZhY1VsaVtwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuVmFjVWxpJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlZhY1VsaSA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuVmFjVWxpLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQpzYXZlKGNvZWZmLnNocnViX2dyYWRpZW50LlZhY1VsaSwgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAiZmlyc3RfcnVuc19jb252ZXJnZWQiLCAibW9kZWxfb3V0cHV0X1ZhY1VsaS5SZGF0YSIpKQ0KIyBsb2FkKGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAiZmlyc3RfcnVuc19jb252ZXJnZWQiLCAibW9kZWxfb3V0cHV0X1ZhY1VsaS5SZGF0YSIpKQ0KDQojIGVmZmVjdCBzaXplIHBsb3QNCihlZmZlY3Rfc2l6ZV9wbG90LlZhY1VsaSA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5WYWNVbGksIHRpdGxlX3N0cmluZyA9ICJWYWNjaW5pdW0gdWxpZ2lub3N1bSIsIHBsb3Rfd2lkdGggPSAxMi41KSkNCg0KYGBgDQoNCiogKipwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBtb3JlIGNvbnNlcnZhdGl2ZSBjb21tdW5pdGllcyBhbmQgVEMgd2V0bmVzcyAoc2lnLikqKg0KKiBzbGlnaHRseSBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBncmFtaW5vaWQgY292ZXIsIHNsaWdodGx5IG5lZ2F0aXZlIHJlbGF0aW9uc2hpcCB3aXRoIHRlcnJhaW4gcnVnZ2VkbmVzcyAobi5zLikNCjxicj4NCg0KQXMgdGhlIHF1YWRyYXRpYyB0ZXJtcyBmb3Igc3VtbWVyIHRlbXBlcmF0dXJlLCBwcmVjaXBpdGF0aW9uIGFuZCB0ZW1wZXJhdHVyZSB2YXJpYWJpbGl0eSB3ZXJlIG5vdCBzaWduaWZpY2FudCwgdGhleSB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgbW9kZWwgYmVmb3JlIHJlLXJ1bm5pbmc6DQpgYGB7cn0NCiMgbmV3IG1vZGVsIG9iamVjdCB3aXRoIHRlcm1zIHJlbW92ZWQNCndyaXRlKCINCiAgDQogIG1vZGVsew0KDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmNvbXBldCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc2hydWJfY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5ncmFtaW5fY292IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zcmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudGN3cyB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBjb250LnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wY29udC54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi5wcmVjaXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnByZWNpcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICBiLnRlbXBYdGN3cyB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBYdGN3czIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgcGhpIH4gZGdhbW1hKDAuMSwgMC4xKQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGRpc2NyZXRlIHBhcnQNCg0KICAgICAgZm9yIChpIGluIDE6Tl9kaXNjcmV0ZSl7IA0KICAgICAgICBjb3YuZGlzW2ldIH4gZGJlcm4obXVbaV0pDQogICAgICAgIGxvZ2l0KG11W2ldKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuZGlzW2ldXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc2hydWJfY292ICogc2hydWJfY292LmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5ncmFtaW5fY292ICogZ3JhbWluX2Nvdi5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcFh0Y3dzICogdGVtcGpqYS5kaXNbaV0gKiB0Y3dzLmRpc1tpXSArICAgICAgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcFh0Y3dzMiAqICh0ZW1wamphLmRpc1tpXV4yKSAqIHRjd3MuZGlzW2ldICsgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRjd3MgKiB0Y3dzLmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuZGlzW2ldICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmRpc1tpXQ0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGNvbnRpbnVvdXMgcGFydA0KDQogICAgICBmb3IgKGogaW4gMTpOX2NvbnQpew0KICAgICAgICBjb3YuY29udFtqXSB+IGRiZXRhKHBbal0sIHFbal0pDQogICAgICAgIHBbal0gPC0gbXUyW2pdICogcGhpDQogICAgICAgIHFbal0gPC0gKDEgLSBtdTJbal0pICogcGhpDQogICAgICAgIGxvZ2l0KG11MltqXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmNvbnRbal1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zaHJ1Yl9jb3YgKiBzaHJ1Yl9jb3YuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLmdyYW1pbl9jb3YgKiBncmFtaW5fY292LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MgKiB0ZW1wamphLmNvbnRbal0gKiB0Y3dzLmNvbnRbal0gKyAgICAgICAjIGZvciBpbnRlcmFjdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBYdGN3czIgKiAodGVtcGpqYS5jb250W2pdXjIpICogdGN3cy5jb250W2pdICsgICMgZm9yIGludGVyYWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRjd3MgKiB0Y3dzLmNvbnRbal0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB0cmkuY29udFtqXQ0KICAgICAgfQ0KDQoNCiAgICAgIGZvciAoayBpbiAxOk5fcGxvdGdyb3Vwcyl7ICMgbGVuZ3RoIG9mIHRvdGFsIHBsb3Rncm91cHMNCiAgICAgICAgYl9wbG90Z3JvdXBba10gfiBkbm9ybShtdS5wbG90Z3JvdXBba10sdGF1LnBsb3Rncm91cCkNCiAgICAgICAgbXUucGxvdGdyb3VwW2tdIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIyBwbG90IGdyb3VwIGxldmVsIHByZWRpY3RvcnMsIGxpbmVhciBhbmQgcXVhZHJhdGljIHRlcm0NCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wamphLnggKiB0ZW1wamphLnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBjb250LngyICogKHRlbXBjb250LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiBwcmVjaXBqamEudG90W2tdICMgKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpIA0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAgICMgYWRkIHByZWRpY3RlZCB2YWx1ZXMgKGRlcml2ZWQgcGFyYW1ldGVycykNCiAgICAgIGZvciAobSBpbiAxOk54aGF0KXsNCiAgICAgICAgcGhhdF9jb21wZXRbbV0gPC0gaW50ZXJjZXB0ICsgYi5jb21wZXQgKiB4aGF0X2NvbXBldFttXQ0KICAgICAgICBwaGF0X2dyYW1pbm9pZF9jb3ZlclttXSA8LSBpbnRlcmNlcHQgKyBiLmdyYW1pbl9jb3YgKiB4aGF0X2dyYW1pbm9pZF9jb3ZlclttXQ0KICAgICAgICBwaGF0X3NocnViX2NvdmVyW21dIDwtIGludGVyY2VwdCArIGIuc2hydWJfY292ICogeGhhdF9zaHJ1Yl9jb3ZlclttXQ0KICAgICAgICBwaGF0X3NyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnNyaSAqIHhoYXRfc3JpW21dDQogICAgICAgIHBoYXRfdHJpW21dIDwtIGludGVyY2VwdCArIGIudHJpICogeGhhdF90cmlbbV0NCiAgICAgICAgcGhhdF90Y3dzW21dIDwtIGludGVyY2VwdCArIGIudGN3cyAqIHhoYXRfdGN3c1ttXQ0KICAgICAgICBwaGF0X3RlbXBqamFbbV0gPC0gaW50ZXJjZXB0ICsgYi50ZW1wamphLnggKiB4aGF0X3RlbXBqamFbbV0gIyArIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamFbbV1eMikNCiAgICAgICAgcGhhdF90ZW1wY29udFttXSA8LSBpbnRlcmNlcHQgKyBiLnRlbXBjb250LnggKiB4aGF0X3RlbXBjb250W21dICMgKyBiLnRlbXBjb250LngyICogKHhoYXRfdGVtcGNvbnRbbV1eMikNCiAgICAgICAgcGhhdF9wcmVjaXBqamFbbV0gPC0gaW50ZXJjZXB0ICsgYi5wcmVjaXBqamEueCAqIHhoYXRfcHJlY2lwamphW21dICMgKyBiLnByZWNpcGpqYS54MiAqICh4aGF0X3ByZWNpcGpqYVttXV4yKQ0KICAgICAgDQogICAgICAgIGZvciAocCBpbiAxOk54aGF0Mil7DQogICAgICAgICAgcGhhdF90ZW1wWG1vaXN0W20scF0gPC0gaW50ZXJjZXB0ICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wamphLnggKiB4aGF0X3RlbXBqamFbbV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamFbbV1eMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRjd3MgKiB4aGF0X3Rjd3MyW3BdICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wWHRjd3MgKiB4aGF0X3RlbXBqamFbbV0gKiB4aGF0X3Rjd3MyW3BdICMgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcFh0Y3dzMiAqICh4aGF0X3RlbXBqamFbbV1eMikgKiB4aGF0X3Rjd3MyW3BdDQogICAgICAgICAgfQ0KICAgICAgICB9DQoNCiAgICANCiAgICAgIH0NCiAgIiwgZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5WYWNVbGkyLmphZ3MiKSkNCg0KIyBzcGVjaWZ5IG5ldyBzZXQgb2YgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQNCnBhcmFtc19WYWNVbGkyIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgICJiLnRlbXBqamEueCIsICMgImIudGVtcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnRlbXBjb250LngiLCAjICJiLnRlbXBjb250LngyIiwNCiAgICAgICAgICAgICAgICAgICAgImIucHJlY2lwamphLngiLCAjICJiLnByZWNpcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLmNvbXBldCIsDQogICAgICAgICAgICAgICAgICAgICJiLnNocnViX2NvdiIsDQogICAgICAgICAgICAgICAgICAgICJiLmdyYW1pbl9jb3YiLA0KICAgICAgICAgICAgICAgICAgICAiYi5zcmkiLA0KICAgICAgICAgICAgICAgICAgICAiYi50cmkiLA0KICAgICAgICAgICAgICAgICAgICAiYi50Y3dzIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc2hydWJfY292ZXIiLCAicGhhdF9ncmFtaW5vaWRfY292ZXIiLCANCiAgICAgICAgICAgICAgICAgICAgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdGN3cyIsIA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wamphIiwgInBoYXRfdGVtcGNvbnQiLCAicGhhdF9wcmVjaXBqamEiLA0KICAgICAgICAgICAgICAgICAgICAicGhhdF90ZW1wWG1vaXN0IikNCg0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaTIgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLlZhY1VsaS5kYXRhLCAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXNfVmFjVWxpMiwgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHNfdGN3cyIsICJzaHJ1Yl9ncmFkaWVudC5WYWNVbGkyLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuVmFjVWxpMikgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLlZhY1VsaTIgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLlZhY1VsaTJbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlZhY1VsaTJbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaTIkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuVmFjVWxpMiA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLlZhY1VsaTIsIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCnNhdmUoY29lZmYuc2hydWJfZ3JhZGllbnQuVmFjVWxpMiwgZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibW9kZWxfb3V0cHV0cyIsICJzcGVjaWVzX3Rjd3MiLCAibW9kZWxfb3V0cHV0X1ZhY1VsaTIuUmRhdGEiKSkNCg0KIyBlZmZlY3Qgc2l6ZSBwbG90DQooZWZmZWN0X3NpemVfcGxvdC5WYWNVbGkyIDwtIG1vZGVsX3Bsb3RfbWFyZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyLCB0aXRsZV9zdHJpbmcgPSAiVmFjY2luaXVtIHVsaWdpbm9zdW0iLCBwbG90X3dpZHRoID0gOS41KSkNCg0KYGBgDQoNCiogKipwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBtb3JlIGNvbnNlcnZhdGl2ZSBjb21tdW5pdGllcywgVEN3ZXRuZXNzIChzaWcuKSoqIGFuZCAqc3VtbWVyIHRlbXBlcmF0dXJlIChtLnMuKSoNCiogc2xpZ2h0bHkgcG9zaXRpdmUgcmVsYXRpb25zaGlwIHdpdGggZ3JhbWlub2lkIGNvdmVyIGFuZCBwcmVjaXBpdGF0aW9uLCBuZWdhdGl2ZSB3aXRoIHRlcnJhaW4gaGV0ZXJvZ2VuZWl0eSAobi5zLikNCg0KPGJyPg0K